1730554d9SArtem B. Bityutskiy /* 2730554d9SArtem B. Bityutskiy * JFFS2 -- Journalling Flash File System, Version 2. 3730554d9SArtem B. Bityutskiy * 4c00c310eSDavid Woodhouse * Copyright © 2001-2007 Red Hat, Inc. 5730554d9SArtem B. Bityutskiy * 6730554d9SArtem B. Bityutskiy * Created by David Woodhouse <dwmw2@infradead.org> 7730554d9SArtem B. Bityutskiy * 8730554d9SArtem B. Bityutskiy * For licensing information, see the file 'LICENCE' in this directory. 9730554d9SArtem B. Bityutskiy * 10730554d9SArtem B. Bityutskiy */ 11c00c310eSDavid Woodhouse 12730554d9SArtem B. Bityutskiy #include <linux/kernel.h> 13737b7661SAndrew Lunn #include <linux/types.h> 14730554d9SArtem B. Bityutskiy #include <linux/pagemap.h> 15e0c8e42fSArtem B. Bityutskiy #include <linux/crc32.h> 16e0c8e42fSArtem B. Bityutskiy #include <linux/jffs2.h> 17733802d9SArtem B. Bityutskiy #include <linux/mtd/mtd.h> 18730554d9SArtem B. Bityutskiy #include "nodelist.h" 19730554d9SArtem B. Bityutskiy #include "debug.h" 20730554d9SArtem B. Bityutskiy 2145ca1b50SArtem B. Bityutskiy #ifdef JFFS2_DBG_SANITY_CHECKS 2245ca1b50SArtem B. Bityutskiy 2345ca1b50SArtem B. Bityutskiy void 2445ca1b50SArtem B. Bityutskiy __jffs2_dbg_acct_sanity_check_nolock(struct jffs2_sb_info *c, 2545ca1b50SArtem B. Bityutskiy struct jffs2_eraseblock *jeb) 2645ca1b50SArtem B. Bityutskiy { 2745ca1b50SArtem B. Bityutskiy if (unlikely(jeb && jeb->used_size + jeb->dirty_size + 2845ca1b50SArtem B. Bityutskiy jeb->free_size + jeb->wasted_size + 2945ca1b50SArtem B. Bityutskiy jeb->unchecked_size != c->sector_size)) { 3045ca1b50SArtem B. Bityutskiy JFFS2_ERROR("eeep, space accounting for block at 0x%08x is screwed.\n", jeb->offset); 3181e39cf0SArtem B. Bityutskiy JFFS2_ERROR("free %#08x + dirty %#08x + used %#08x + wasted %#08x + unchecked %#08x != total %#08x.\n", 3281e39cf0SArtem B. Bityutskiy jeb->free_size, jeb->dirty_size, jeb->used_size, 3345ca1b50SArtem B. Bityutskiy jeb->wasted_size, jeb->unchecked_size, c->sector_size); 3445ca1b50SArtem B. Bityutskiy BUG(); 3545ca1b50SArtem B. Bityutskiy } 3645ca1b50SArtem B. Bityutskiy 3745ca1b50SArtem B. Bityutskiy if (unlikely(c->used_size + c->dirty_size + c->free_size + c->erasing_size + c->bad_size 3845ca1b50SArtem B. Bityutskiy + c->wasted_size + c->unchecked_size != c->flash_size)) { 3945ca1b50SArtem B. Bityutskiy JFFS2_ERROR("eeep, space accounting superblock info is screwed.\n"); 4081e39cf0SArtem B. Bityutskiy JFFS2_ERROR("free %#08x + dirty %#08x + used %#08x + erasing %#08x + bad %#08x + wasted %#08x + unchecked %#08x != total %#08x.\n", 4145ca1b50SArtem B. Bityutskiy c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size, 4245ca1b50SArtem B. Bityutskiy c->wasted_size, c->unchecked_size, c->flash_size); 4345ca1b50SArtem B. Bityutskiy BUG(); 4445ca1b50SArtem B. Bityutskiy } 4545ca1b50SArtem B. Bityutskiy } 4645ca1b50SArtem B. Bityutskiy 4745ca1b50SArtem B. Bityutskiy void 4845ca1b50SArtem B. Bityutskiy __jffs2_dbg_acct_sanity_check(struct jffs2_sb_info *c, 4945ca1b50SArtem B. Bityutskiy struct jffs2_eraseblock *jeb) 5045ca1b50SArtem B. Bityutskiy { 5145ca1b50SArtem B. Bityutskiy spin_lock(&c->erase_completion_lock); 5245ca1b50SArtem B. Bityutskiy jffs2_dbg_acct_sanity_check_nolock(c, jeb); 5345ca1b50SArtem B. Bityutskiy spin_unlock(&c->erase_completion_lock); 5445ca1b50SArtem B. Bityutskiy } 5545ca1b50SArtem B. Bityutskiy 5645ca1b50SArtem B. Bityutskiy #endif /* JFFS2_DBG_SANITY_CHECKS */ 5745ca1b50SArtem B. Bityutskiy 58730554d9SArtem B. Bityutskiy #ifdef JFFS2_DBG_PARANOIA_CHECKS 59e0c8e42fSArtem B. Bityutskiy /* 60e0c8e42fSArtem B. Bityutskiy * Check the fragtree. 61e0c8e42fSArtem B. Bityutskiy */ 62e0c8e42fSArtem B. Bityutskiy void 63e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_fragtree_paranoia_check(struct jffs2_inode_info *f) 64e0c8e42fSArtem B. Bityutskiy { 65ced22070SDavid Woodhouse mutex_lock(&f->sem); 66e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_fragtree_paranoia_check_nolock(f); 67ced22070SDavid Woodhouse mutex_unlock(&f->sem); 68e0c8e42fSArtem B. Bityutskiy } 69730554d9SArtem B. Bityutskiy 70730554d9SArtem B. Bityutskiy void 71e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_fragtree_paranoia_check_nolock(struct jffs2_inode_info *f) 72730554d9SArtem B. Bityutskiy { 73730554d9SArtem B. Bityutskiy struct jffs2_node_frag *frag; 74730554d9SArtem B. Bityutskiy int bitched = 0; 75730554d9SArtem B. Bityutskiy 76730554d9SArtem B. Bityutskiy for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) { 77730554d9SArtem B. Bityutskiy struct jffs2_full_dnode *fn = frag->node; 78730554d9SArtem B. Bityutskiy 79730554d9SArtem B. Bityutskiy if (!fn || !fn->raw) 80730554d9SArtem B. Bityutskiy continue; 81730554d9SArtem B. Bityutskiy 82730554d9SArtem B. Bityutskiy if (ref_flags(fn->raw) == REF_PRISTINE) { 83730554d9SArtem B. Bityutskiy if (fn->frags > 1) { 84e0c8e42fSArtem B. Bityutskiy JFFS2_ERROR("REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2.\n", 85730554d9SArtem B. Bityutskiy ref_offset(fn->raw), fn->frags); 86730554d9SArtem B. Bityutskiy bitched = 1; 87730554d9SArtem B. Bityutskiy } 88730554d9SArtem B. Bityutskiy 89730554d9SArtem B. Bityutskiy /* A hole node which isn't multi-page should be garbage-collected 90730554d9SArtem B. Bityutskiy and merged anyway, so we just check for the frag size here, 91730554d9SArtem B. Bityutskiy rather than mucking around with actually reading the node 92730554d9SArtem B. Bityutskiy and checking the compression type, which is the real way 93730554d9SArtem B. Bityutskiy to tell a hole node. */ 94730554d9SArtem B. Bityutskiy if (frag->ofs & (PAGE_CACHE_SIZE-1) && frag_prev(frag) 95730554d9SArtem B. Bityutskiy && frag_prev(frag)->size < PAGE_CACHE_SIZE && frag_prev(frag)->node) { 9681e39cf0SArtem B. Bityutskiy JFFS2_ERROR("REF_PRISTINE node at 0x%08x had a previous non-hole frag in the same page. Tell dwmw2.\n", 9781e39cf0SArtem B. Bityutskiy ref_offset(fn->raw)); 98730554d9SArtem B. Bityutskiy bitched = 1; 99730554d9SArtem B. Bityutskiy } 100730554d9SArtem B. Bityutskiy 101730554d9SArtem B. Bityutskiy if ((frag->ofs+frag->size) & (PAGE_CACHE_SIZE-1) && frag_next(frag) 102730554d9SArtem B. Bityutskiy && frag_next(frag)->size < PAGE_CACHE_SIZE && frag_next(frag)->node) { 10381e39cf0SArtem 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", 104730554d9SArtem B. Bityutskiy ref_offset(fn->raw), frag->ofs, frag->ofs+frag->size); 105730554d9SArtem B. Bityutskiy bitched = 1; 106730554d9SArtem B. Bityutskiy } 107730554d9SArtem B. Bityutskiy } 108730554d9SArtem B. Bityutskiy } 109730554d9SArtem B. Bityutskiy 110730554d9SArtem B. Bityutskiy if (bitched) { 111e0c8e42fSArtem B. Bityutskiy JFFS2_ERROR("fragtree is corrupted.\n"); 112e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_fragtree_nolock(f); 113730554d9SArtem B. Bityutskiy BUG(); 114730554d9SArtem B. Bityutskiy } 115730554d9SArtem B. Bityutskiy } 116730554d9SArtem B. Bityutskiy 117730554d9SArtem B. Bityutskiy /* 118730554d9SArtem B. Bityutskiy * Check if the flash contains all 0xFF before we start writing. 119730554d9SArtem B. Bityutskiy */ 120730554d9SArtem B. Bityutskiy void 121e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_prewrite_paranoia_check(struct jffs2_sb_info *c, 122e0c8e42fSArtem B. Bityutskiy uint32_t ofs, int len) 123730554d9SArtem B. Bityutskiy { 124730554d9SArtem B. Bityutskiy size_t retlen; 125730554d9SArtem B. Bityutskiy int ret, i; 126730554d9SArtem B. Bityutskiy unsigned char *buf; 127730554d9SArtem B. Bityutskiy 128730554d9SArtem B. Bityutskiy buf = kmalloc(len, GFP_KERNEL); 129730554d9SArtem B. Bityutskiy if (!buf) 130730554d9SArtem B. Bityutskiy return; 131730554d9SArtem B. Bityutskiy 132730554d9SArtem B. Bityutskiy ret = jffs2_flash_read(c, ofs, len, &retlen, buf); 133730554d9SArtem B. Bityutskiy if (ret || (retlen != len)) { 134e0c8e42fSArtem B. Bityutskiy JFFS2_WARNING("read %d bytes failed or short. ret %d, retlen %zd.\n", 135e0c8e42fSArtem B. Bityutskiy len, ret, retlen); 136730554d9SArtem B. Bityutskiy kfree(buf); 137730554d9SArtem B. Bityutskiy return; 138730554d9SArtem B. Bityutskiy } 139730554d9SArtem B. Bityutskiy 140730554d9SArtem B. Bityutskiy ret = 0; 141730554d9SArtem B. Bityutskiy for (i = 0; i < len; i++) 142730554d9SArtem B. Bityutskiy if (buf[i] != 0xff) 143730554d9SArtem B. Bityutskiy ret = 1; 144730554d9SArtem B. Bityutskiy 145730554d9SArtem B. Bityutskiy if (ret) { 14681e39cf0SArtem 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", 14781e39cf0SArtem B. Bityutskiy ofs, ofs + i); 148e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_buffer(buf, len, ofs); 149730554d9SArtem B. Bityutskiy kfree(buf); 150730554d9SArtem B. Bityutskiy BUG(); 151730554d9SArtem B. Bityutskiy } 152730554d9SArtem B. Bityutskiy 153730554d9SArtem B. Bityutskiy kfree(buf); 154730554d9SArtem B. Bityutskiy } 155730554d9SArtem B. Bityutskiy 156*85a62db6SDavid Woodhouse void __jffs2_dbg_superblock_counts(struct jffs2_sb_info *c) 157*85a62db6SDavid Woodhouse { 158*85a62db6SDavid Woodhouse struct jffs2_eraseblock *jeb; 159*85a62db6SDavid Woodhouse uint32_t free = 0, dirty = 0, used = 0, wasted = 0, 160*85a62db6SDavid Woodhouse erasing = 0, bad = 0, unchecked = 0; 161*85a62db6SDavid Woodhouse int nr_counted = 0; 162*85a62db6SDavid Woodhouse int dump = 0; 163*85a62db6SDavid Woodhouse 164*85a62db6SDavid Woodhouse if (c->gcblock) { 165*85a62db6SDavid Woodhouse nr_counted++; 166*85a62db6SDavid Woodhouse free += c->gcblock->free_size; 167*85a62db6SDavid Woodhouse dirty += c->gcblock->dirty_size; 168*85a62db6SDavid Woodhouse used += c->gcblock->used_size; 169*85a62db6SDavid Woodhouse wasted += c->gcblock->wasted_size; 170*85a62db6SDavid Woodhouse unchecked += c->gcblock->unchecked_size; 171*85a62db6SDavid Woodhouse } 172*85a62db6SDavid Woodhouse if (c->nextblock) { 173*85a62db6SDavid Woodhouse nr_counted++; 174*85a62db6SDavid Woodhouse free += c->nextblock->free_size; 175*85a62db6SDavid Woodhouse dirty += c->nextblock->dirty_size; 176*85a62db6SDavid Woodhouse used += c->nextblock->used_size; 177*85a62db6SDavid Woodhouse wasted += c->nextblock->wasted_size; 178*85a62db6SDavid Woodhouse unchecked += c->nextblock->unchecked_size; 179*85a62db6SDavid Woodhouse } 180*85a62db6SDavid Woodhouse list_for_each_entry(jeb, &c->clean_list, list) { 181*85a62db6SDavid Woodhouse nr_counted++; 182*85a62db6SDavid Woodhouse free += jeb->free_size; 183*85a62db6SDavid Woodhouse dirty += jeb->dirty_size; 184*85a62db6SDavid Woodhouse used += jeb->used_size; 185*85a62db6SDavid Woodhouse wasted += jeb->wasted_size; 186*85a62db6SDavid Woodhouse unchecked += jeb->unchecked_size; 187*85a62db6SDavid Woodhouse } 188*85a62db6SDavid Woodhouse list_for_each_entry(jeb, &c->very_dirty_list, list) { 189*85a62db6SDavid Woodhouse nr_counted++; 190*85a62db6SDavid Woodhouse free += jeb->free_size; 191*85a62db6SDavid Woodhouse dirty += jeb->dirty_size; 192*85a62db6SDavid Woodhouse used += jeb->used_size; 193*85a62db6SDavid Woodhouse wasted += jeb->wasted_size; 194*85a62db6SDavid Woodhouse unchecked += jeb->unchecked_size; 195*85a62db6SDavid Woodhouse } 196*85a62db6SDavid Woodhouse list_for_each_entry(jeb, &c->dirty_list, list) { 197*85a62db6SDavid Woodhouse nr_counted++; 198*85a62db6SDavid Woodhouse free += jeb->free_size; 199*85a62db6SDavid Woodhouse dirty += jeb->dirty_size; 200*85a62db6SDavid Woodhouse used += jeb->used_size; 201*85a62db6SDavid Woodhouse wasted += jeb->wasted_size; 202*85a62db6SDavid Woodhouse unchecked += jeb->unchecked_size; 203*85a62db6SDavid Woodhouse } 204*85a62db6SDavid Woodhouse list_for_each_entry(jeb, &c->erasable_list, list) { 205*85a62db6SDavid Woodhouse nr_counted++; 206*85a62db6SDavid Woodhouse free += jeb->free_size; 207*85a62db6SDavid Woodhouse dirty += jeb->dirty_size; 208*85a62db6SDavid Woodhouse used += jeb->used_size; 209*85a62db6SDavid Woodhouse wasted += jeb->wasted_size; 210*85a62db6SDavid Woodhouse unchecked += jeb->unchecked_size; 211*85a62db6SDavid Woodhouse } 212*85a62db6SDavid Woodhouse list_for_each_entry(jeb, &c->erasable_pending_wbuf_list, list) { 213*85a62db6SDavid Woodhouse nr_counted++; 214*85a62db6SDavid Woodhouse free += jeb->free_size; 215*85a62db6SDavid Woodhouse dirty += jeb->dirty_size; 216*85a62db6SDavid Woodhouse used += jeb->used_size; 217*85a62db6SDavid Woodhouse wasted += jeb->wasted_size; 218*85a62db6SDavid Woodhouse unchecked += jeb->unchecked_size; 219*85a62db6SDavid Woodhouse } 220*85a62db6SDavid Woodhouse list_for_each_entry(jeb, &c->erase_pending_list, list) { 221*85a62db6SDavid Woodhouse nr_counted++; 222*85a62db6SDavid Woodhouse free += jeb->free_size; 223*85a62db6SDavid Woodhouse dirty += jeb->dirty_size; 224*85a62db6SDavid Woodhouse used += jeb->used_size; 225*85a62db6SDavid Woodhouse wasted += jeb->wasted_size; 226*85a62db6SDavid Woodhouse unchecked += jeb->unchecked_size; 227*85a62db6SDavid Woodhouse } 228*85a62db6SDavid Woodhouse list_for_each_entry(jeb, &c->free_list, list) { 229*85a62db6SDavid Woodhouse nr_counted++; 230*85a62db6SDavid Woodhouse free += jeb->free_size; 231*85a62db6SDavid Woodhouse dirty += jeb->dirty_size; 232*85a62db6SDavid Woodhouse used += jeb->used_size; 233*85a62db6SDavid Woodhouse wasted += jeb->wasted_size; 234*85a62db6SDavid Woodhouse unchecked += jeb->unchecked_size; 235*85a62db6SDavid Woodhouse } 236*85a62db6SDavid Woodhouse list_for_each_entry(jeb, &c->bad_used_list, list) { 237*85a62db6SDavid Woodhouse nr_counted++; 238*85a62db6SDavid Woodhouse free += jeb->free_size; 239*85a62db6SDavid Woodhouse dirty += jeb->dirty_size; 240*85a62db6SDavid Woodhouse used += jeb->used_size; 241*85a62db6SDavid Woodhouse wasted += jeb->wasted_size; 242*85a62db6SDavid Woodhouse unchecked += jeb->unchecked_size; 243*85a62db6SDavid Woodhouse } 244*85a62db6SDavid Woodhouse 245*85a62db6SDavid Woodhouse list_for_each_entry(jeb, &c->erasing_list, list) { 246*85a62db6SDavid Woodhouse nr_counted++; 247*85a62db6SDavid Woodhouse erasing += c->sector_size; 248*85a62db6SDavid Woodhouse } 249*85a62db6SDavid Woodhouse list_for_each_entry(jeb, &c->erase_complete_list, list) { 250*85a62db6SDavid Woodhouse nr_counted++; 251*85a62db6SDavid Woodhouse erasing += c->sector_size; 252*85a62db6SDavid Woodhouse } 253*85a62db6SDavid Woodhouse list_for_each_entry(jeb, &c->bad_list, list) { 254*85a62db6SDavid Woodhouse nr_counted++; 255*85a62db6SDavid Woodhouse bad += c->sector_size; 256*85a62db6SDavid Woodhouse } 257*85a62db6SDavid Woodhouse 258*85a62db6SDavid Woodhouse #define check(sz) \ 259*85a62db6SDavid Woodhouse if (sz != c->sz##_size) { \ 260*85a62db6SDavid Woodhouse printk(KERN_WARNING #sz "_size mismatch counted 0x%x, c->" #sz "_size 0x%x\n", \ 261*85a62db6SDavid Woodhouse sz, c->sz##_size); \ 262*85a62db6SDavid Woodhouse dump = 1; \ 263*85a62db6SDavid Woodhouse } 264*85a62db6SDavid Woodhouse check(free); 265*85a62db6SDavid Woodhouse check(dirty); 266*85a62db6SDavid Woodhouse check(used); 267*85a62db6SDavid Woodhouse check(wasted); 268*85a62db6SDavid Woodhouse check(unchecked); 269*85a62db6SDavid Woodhouse check(bad); 270*85a62db6SDavid Woodhouse check(erasing); 271*85a62db6SDavid Woodhouse #undef check 272*85a62db6SDavid Woodhouse 273*85a62db6SDavid Woodhouse if (nr_counted != c->nr_blocks) { 274*85a62db6SDavid Woodhouse printk(KERN_WARNING "%s counted only 0x%x blocks of 0x%x. Where are the others?\n", 275*85a62db6SDavid Woodhouse __func__, nr_counted, c->nr_blocks); 276*85a62db6SDavid Woodhouse dump = 1; 277*85a62db6SDavid Woodhouse } 278*85a62db6SDavid Woodhouse 279*85a62db6SDavid Woodhouse if (dump) { 280*85a62db6SDavid Woodhouse __jffs2_dbg_dump_block_lists_nolock(c); 281*85a62db6SDavid Woodhouse BUG(); 282*85a62db6SDavid Woodhouse } 283*85a62db6SDavid Woodhouse } 284*85a62db6SDavid Woodhouse 285730554d9SArtem B. Bityutskiy /* 286730554d9SArtem B. Bityutskiy * Check the space accounting and node_ref list correctness for the JFFS2 erasable block 'jeb'. 287730554d9SArtem B. Bityutskiy */ 288730554d9SArtem B. Bityutskiy void 289e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_acct_paranoia_check(struct jffs2_sb_info *c, 290e0c8e42fSArtem B. Bityutskiy struct jffs2_eraseblock *jeb) 291e0c8e42fSArtem B. Bityutskiy { 292e0c8e42fSArtem B. Bityutskiy spin_lock(&c->erase_completion_lock); 293e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_acct_paranoia_check_nolock(c, jeb); 294e0c8e42fSArtem B. Bityutskiy spin_unlock(&c->erase_completion_lock); 295e0c8e42fSArtem B. Bityutskiy } 296e0c8e42fSArtem B. Bityutskiy 297e0c8e42fSArtem B. Bityutskiy void 298e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_acct_paranoia_check_nolock(struct jffs2_sb_info *c, 299e0c8e42fSArtem B. Bityutskiy struct jffs2_eraseblock *jeb) 300730554d9SArtem B. Bityutskiy { 301730554d9SArtem B. Bityutskiy uint32_t my_used_size = 0; 302730554d9SArtem B. Bityutskiy uint32_t my_unchecked_size = 0; 303730554d9SArtem B. Bityutskiy uint32_t my_dirty_size = 0; 304730554d9SArtem B. Bityutskiy struct jffs2_raw_node_ref *ref2 = jeb->first_node; 305730554d9SArtem B. Bityutskiy 306730554d9SArtem B. Bityutskiy while (ref2) { 307730554d9SArtem B. Bityutskiy uint32_t totlen = ref_totlen(c, jeb, ref2); 308730554d9SArtem B. Bityutskiy 309abb536e7SKyungmin Park if (ref_offset(ref2) < jeb->offset || 310abb536e7SKyungmin Park ref_offset(ref2) > jeb->offset + c->sector_size) { 311e0c8e42fSArtem B. Bityutskiy JFFS2_ERROR("node_ref %#08x shouldn't be in block at %#08x.\n", 312730554d9SArtem B. Bityutskiy ref_offset(ref2), jeb->offset); 313e0c8e42fSArtem B. Bityutskiy goto error; 314730554d9SArtem B. Bityutskiy 315730554d9SArtem B. Bityutskiy } 316730554d9SArtem B. Bityutskiy if (ref_flags(ref2) == REF_UNCHECKED) 317730554d9SArtem B. Bityutskiy my_unchecked_size += totlen; 318730554d9SArtem B. Bityutskiy else if (!ref_obsolete(ref2)) 319730554d9SArtem B. Bityutskiy my_used_size += totlen; 320730554d9SArtem B. Bityutskiy else 321730554d9SArtem B. Bityutskiy my_dirty_size += totlen; 322730554d9SArtem B. Bityutskiy 32399988f7bSDavid Woodhouse if ((!ref_next(ref2)) != (ref2 == jeb->last_node)) { 32499988f7bSDavid 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", 32599988f7bSDavid Woodhouse ref_offset(ref2), ref2, ref_offset(ref_next(ref2)), ref_next(ref2), 326730554d9SArtem B. Bityutskiy ref_offset(jeb->last_node), jeb->last_node); 327e0c8e42fSArtem B. Bityutskiy goto error; 328730554d9SArtem B. Bityutskiy } 32999988f7bSDavid Woodhouse ref2 = ref_next(ref2); 330730554d9SArtem B. Bityutskiy } 331730554d9SArtem B. Bityutskiy 332730554d9SArtem B. Bityutskiy if (my_used_size != jeb->used_size) { 333e0c8e42fSArtem B. Bityutskiy JFFS2_ERROR("Calculated used size %#08x != stored used size %#08x.\n", 334730554d9SArtem B. Bityutskiy my_used_size, jeb->used_size); 335e0c8e42fSArtem B. Bityutskiy goto error; 336730554d9SArtem B. Bityutskiy } 337730554d9SArtem B. Bityutskiy 338730554d9SArtem B. Bityutskiy if (my_unchecked_size != jeb->unchecked_size) { 339e0c8e42fSArtem B. Bityutskiy JFFS2_ERROR("Calculated unchecked size %#08x != stored unchecked size %#08x.\n", 340730554d9SArtem B. Bityutskiy my_unchecked_size, jeb->unchecked_size); 341e0c8e42fSArtem B. Bityutskiy goto error; 342730554d9SArtem B. Bityutskiy } 343730554d9SArtem B. Bityutskiy 344e0c8e42fSArtem B. Bityutskiy #if 0 345e0c8e42fSArtem B. Bityutskiy /* This should work when we implement ref->__totlen elemination */ 346730554d9SArtem B. Bityutskiy if (my_dirty_size != jeb->dirty_size + jeb->wasted_size) { 347e0c8e42fSArtem B. Bityutskiy JFFS2_ERROR("Calculated dirty+wasted size %#08x != stored dirty + wasted size %#08x\n", 348730554d9SArtem B. Bityutskiy my_dirty_size, jeb->dirty_size + jeb->wasted_size); 349e0c8e42fSArtem B. Bityutskiy goto error; 350730554d9SArtem B. Bityutskiy } 351730554d9SArtem B. Bityutskiy 352730554d9SArtem B. Bityutskiy if (jeb->free_size == 0 353730554d9SArtem B. Bityutskiy && my_used_size + my_unchecked_size + my_dirty_size != c->sector_size) { 354e0c8e42fSArtem B. Bityutskiy JFFS2_ERROR("The sum of all nodes in block (%#x) != size of block (%#x)\n", 355730554d9SArtem B. Bityutskiy my_used_size + my_unchecked_size + my_dirty_size, 356730554d9SArtem B. Bityutskiy c->sector_size); 357e0c8e42fSArtem B. Bityutskiy goto error; 358730554d9SArtem B. Bityutskiy } 359e0c8e42fSArtem B. Bityutskiy #endif 360730554d9SArtem B. Bityutskiy 361*85a62db6SDavid Woodhouse if (!(c->flags & (JFFS2_SB_FLAG_BUILDING|JFFS2_SB_FLAG_SCANNING))) 362*85a62db6SDavid Woodhouse __jffs2_dbg_superblock_counts(c); 363*85a62db6SDavid Woodhouse 364e0c8e42fSArtem B. Bityutskiy return; 365e0c8e42fSArtem B. Bityutskiy 366e0c8e42fSArtem B. Bityutskiy error: 367e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_node_refs_nolock(c, jeb); 368e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_jeb_nolock(jeb); 369e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_block_lists_nolock(c); 370e0c8e42fSArtem B. Bityutskiy BUG(); 371e0c8e42fSArtem B. Bityutskiy 372e0c8e42fSArtem B. Bityutskiy } 373e0c8e42fSArtem B. Bityutskiy #endif /* JFFS2_DBG_PARANOIA_CHECKS */ 374e0c8e42fSArtem B. Bityutskiy 375e0c8e42fSArtem B. Bityutskiy #if defined(JFFS2_DBG_DUMPS) || defined(JFFS2_DBG_PARANOIA_CHECKS) 376730554d9SArtem B. Bityutskiy /* 377730554d9SArtem B. Bityutskiy * Dump the node_refs of the 'jeb' JFFS2 eraseblock. 378730554d9SArtem B. Bityutskiy */ 379730554d9SArtem B. Bityutskiy void 380e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_node_refs(struct jffs2_sb_info *c, 381e0c8e42fSArtem B. Bityutskiy struct jffs2_eraseblock *jeb) 382e0c8e42fSArtem B. Bityutskiy { 383e0c8e42fSArtem B. Bityutskiy spin_lock(&c->erase_completion_lock); 384e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_node_refs_nolock(c, jeb); 385e0c8e42fSArtem B. Bityutskiy spin_unlock(&c->erase_completion_lock); 386e0c8e42fSArtem B. Bityutskiy } 387e0c8e42fSArtem B. Bityutskiy 388e0c8e42fSArtem B. Bityutskiy void 389e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_node_refs_nolock(struct jffs2_sb_info *c, 390e0c8e42fSArtem B. Bityutskiy struct jffs2_eraseblock *jeb) 391730554d9SArtem B. Bityutskiy { 392730554d9SArtem B. Bityutskiy struct jffs2_raw_node_ref *ref; 393730554d9SArtem B. Bityutskiy int i = 0; 394730554d9SArtem B. Bityutskiy 39581e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG_MSG_PREFIX " Dump node_refs of the eraseblock %#08x\n", jeb->offset); 396730554d9SArtem B. Bityutskiy if (!jeb->first_node) { 39781e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG_MSG_PREFIX " no nodes in the eraseblock %#08x\n", jeb->offset); 398730554d9SArtem B. Bityutskiy return; 399730554d9SArtem B. Bityutskiy } 400730554d9SArtem B. Bityutskiy 40181e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG); 40299988f7bSDavid Woodhouse for (ref = jeb->first_node; ; ref = ref_next(ref)) { 403730554d9SArtem B. Bityutskiy printk("%#08x(%#x)", ref_offset(ref), ref->__totlen); 40499988f7bSDavid Woodhouse if (ref_next(ref)) 405730554d9SArtem B. Bityutskiy printk("->"); 406730554d9SArtem B. Bityutskiy else 407730554d9SArtem B. Bityutskiy break; 408730554d9SArtem B. Bityutskiy if (++i == 4) { 409730554d9SArtem B. Bityutskiy i = 0; 41081e39cf0SArtem B. Bityutskiy printk("\n" JFFS2_DBG); 411730554d9SArtem B. Bityutskiy } 412730554d9SArtem B. Bityutskiy } 413730554d9SArtem B. Bityutskiy printk("\n"); 414730554d9SArtem B. Bityutskiy } 415730554d9SArtem B. Bityutskiy 416e0c8e42fSArtem B. Bityutskiy /* 417e0c8e42fSArtem B. Bityutskiy * Dump an eraseblock's space accounting. 418e0c8e42fSArtem B. Bityutskiy */ 419730554d9SArtem B. Bityutskiy void 420e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) 421730554d9SArtem B. Bityutskiy { 422e0c8e42fSArtem B. Bityutskiy spin_lock(&c->erase_completion_lock); 423e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_jeb_nolock(jeb); 424e0c8e42fSArtem B. Bityutskiy spin_unlock(&c->erase_completion_lock); 425e0c8e42fSArtem B. Bityutskiy } 426e0c8e42fSArtem B. Bityutskiy 427e0c8e42fSArtem B. Bityutskiy void 428e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_jeb_nolock(struct jffs2_eraseblock *jeb) 429e0c8e42fSArtem B. Bityutskiy { 430e0c8e42fSArtem B. Bityutskiy if (!jeb) 431e0c8e42fSArtem B. Bityutskiy return; 432e0c8e42fSArtem B. Bityutskiy 43381e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG_MSG_PREFIX " dump space accounting for the eraseblock at %#08x:\n", 434e0c8e42fSArtem B. Bityutskiy jeb->offset); 435e0c8e42fSArtem B. Bityutskiy 43681e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "used_size: %#08x\n", jeb->used_size); 43781e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "dirty_size: %#08x\n", jeb->dirty_size); 43881e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "wasted_size: %#08x\n", jeb->wasted_size); 43981e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "unchecked_size: %#08x\n", jeb->unchecked_size); 44081e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "free_size: %#08x\n", jeb->free_size); 441e0c8e42fSArtem B. Bityutskiy } 442e0c8e42fSArtem B. Bityutskiy 443e0c8e42fSArtem B. Bityutskiy void 444e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_block_lists(struct jffs2_sb_info *c) 445e0c8e42fSArtem B. Bityutskiy { 446e0c8e42fSArtem B. Bityutskiy spin_lock(&c->erase_completion_lock); 447e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_block_lists_nolock(c); 448e0c8e42fSArtem B. Bityutskiy spin_unlock(&c->erase_completion_lock); 449e0c8e42fSArtem B. Bityutskiy } 450e0c8e42fSArtem B. Bityutskiy 451e0c8e42fSArtem B. Bityutskiy void 452e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_block_lists_nolock(struct jffs2_sb_info *c) 453e0c8e42fSArtem B. Bityutskiy { 45481e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG_MSG_PREFIX " dump JFFS2 blocks lists:\n"); 455e0c8e42fSArtem B. Bityutskiy 45681e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "flash_size: %#08x\n", c->flash_size); 45781e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "used_size: %#08x\n", c->used_size); 45881e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "dirty_size: %#08x\n", c->dirty_size); 45981e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "wasted_size: %#08x\n", c->wasted_size); 46081e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "unchecked_size: %#08x\n", c->unchecked_size); 46181e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "free_size: %#08x\n", c->free_size); 46281e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "erasing_size: %#08x\n", c->erasing_size); 46381e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "bad_size: %#08x\n", c->bad_size); 46481e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "sector_size: %#08x\n", c->sector_size); 46581e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "jffs2_reserved_blocks size: %#08x\n", 466730554d9SArtem B. Bityutskiy c->sector_size * c->resv_blocks_write); 467730554d9SArtem B. Bityutskiy 468730554d9SArtem B. Bityutskiy if (c->nextblock) 46981e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "nextblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 470730554d9SArtem B. Bityutskiy c->nextblock->offset, c->nextblock->used_size, 471730554d9SArtem B. Bityutskiy c->nextblock->dirty_size, c->nextblock->wasted_size, 472730554d9SArtem B. Bityutskiy c->nextblock->unchecked_size, c->nextblock->free_size); 473730554d9SArtem B. Bityutskiy else 47481e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "nextblock: NULL\n"); 475730554d9SArtem B. Bityutskiy 476730554d9SArtem B. Bityutskiy if (c->gcblock) 47781e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "gcblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 478730554d9SArtem B. Bityutskiy c->gcblock->offset, c->gcblock->used_size, c->gcblock->dirty_size, 479730554d9SArtem B. Bityutskiy c->gcblock->wasted_size, c->gcblock->unchecked_size, c->gcblock->free_size); 480730554d9SArtem B. Bityutskiy else 48181e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "gcblock: NULL\n"); 482730554d9SArtem B. Bityutskiy 483730554d9SArtem B. Bityutskiy if (list_empty(&c->clean_list)) { 48481e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "clean_list: empty\n"); 485730554d9SArtem B. Bityutskiy } else { 486730554d9SArtem B. Bityutskiy struct list_head *this; 487730554d9SArtem B. Bityutskiy int numblocks = 0; 488730554d9SArtem B. Bityutskiy uint32_t dirty = 0; 489730554d9SArtem B. Bityutskiy 490730554d9SArtem B. Bityutskiy list_for_each(this, &c->clean_list) { 491730554d9SArtem B. Bityutskiy struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 492730554d9SArtem B. Bityutskiy numblocks ++; 493730554d9SArtem B. Bityutskiy dirty += jeb->wasted_size; 494730554d9SArtem B. Bityutskiy if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 49581e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "clean_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 496730554d9SArtem B. Bityutskiy jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 497730554d9SArtem B. Bityutskiy jeb->unchecked_size, jeb->free_size); 498730554d9SArtem B. Bityutskiy } 499730554d9SArtem B. Bityutskiy } 500730554d9SArtem B. Bityutskiy 50181e39cf0SArtem B. Bityutskiy printk (JFFS2_DBG "Contains %d blocks with total wasted size %u, average wasted size: %u\n", 502730554d9SArtem B. Bityutskiy numblocks, dirty, dirty / numblocks); 503730554d9SArtem B. Bityutskiy } 504730554d9SArtem B. Bityutskiy 505730554d9SArtem B. Bityutskiy if (list_empty(&c->very_dirty_list)) { 50681e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "very_dirty_list: empty\n"); 507730554d9SArtem B. Bityutskiy } else { 508730554d9SArtem B. Bityutskiy struct list_head *this; 509730554d9SArtem B. Bityutskiy int numblocks = 0; 510730554d9SArtem B. Bityutskiy uint32_t dirty = 0; 511730554d9SArtem B. Bityutskiy 512730554d9SArtem B. Bityutskiy list_for_each(this, &c->very_dirty_list) { 513730554d9SArtem B. Bityutskiy struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 514730554d9SArtem B. Bityutskiy 515730554d9SArtem B. Bityutskiy numblocks ++; 516730554d9SArtem B. Bityutskiy dirty += jeb->dirty_size; 517730554d9SArtem B. Bityutskiy if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 51881e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "very_dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 519730554d9SArtem B. Bityutskiy jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 520730554d9SArtem B. Bityutskiy jeb->unchecked_size, jeb->free_size); 521730554d9SArtem B. Bityutskiy } 522730554d9SArtem B. Bityutskiy } 523730554d9SArtem B. Bityutskiy 52481e39cf0SArtem B. Bityutskiy printk (JFFS2_DBG "Contains %d blocks with total dirty size %u, average dirty size: %u\n", 525730554d9SArtem B. Bityutskiy numblocks, dirty, dirty / numblocks); 526730554d9SArtem B. Bityutskiy } 527730554d9SArtem B. Bityutskiy 528730554d9SArtem B. Bityutskiy if (list_empty(&c->dirty_list)) { 52981e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "dirty_list: empty\n"); 530730554d9SArtem B. Bityutskiy } else { 531730554d9SArtem B. Bityutskiy struct list_head *this; 532730554d9SArtem B. Bityutskiy int numblocks = 0; 533730554d9SArtem B. Bityutskiy uint32_t dirty = 0; 534730554d9SArtem B. Bityutskiy 535730554d9SArtem B. Bityutskiy list_for_each(this, &c->dirty_list) { 536730554d9SArtem B. Bityutskiy struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 537730554d9SArtem B. Bityutskiy 538730554d9SArtem B. Bityutskiy numblocks ++; 539730554d9SArtem B. Bityutskiy dirty += jeb->dirty_size; 540730554d9SArtem B. Bityutskiy if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 54181e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 542730554d9SArtem B. Bityutskiy jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 543730554d9SArtem B. Bityutskiy jeb->unchecked_size, jeb->free_size); 544730554d9SArtem B. Bityutskiy } 545730554d9SArtem B. Bityutskiy } 546730554d9SArtem B. Bityutskiy 54781e39cf0SArtem B. Bityutskiy printk (JFFS2_DBG "contains %d blocks with total dirty size %u, average dirty size: %u\n", 548730554d9SArtem B. Bityutskiy numblocks, dirty, dirty / numblocks); 549730554d9SArtem B. Bityutskiy } 550730554d9SArtem B. Bityutskiy 551730554d9SArtem B. Bityutskiy if (list_empty(&c->erasable_list)) { 55281e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "erasable_list: empty\n"); 553730554d9SArtem B. Bityutskiy } else { 554730554d9SArtem B. Bityutskiy struct list_head *this; 555730554d9SArtem B. Bityutskiy 556730554d9SArtem B. Bityutskiy list_for_each(this, &c->erasable_list) { 557730554d9SArtem B. Bityutskiy struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 558730554d9SArtem B. Bityutskiy 559730554d9SArtem B. Bityutskiy if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 56081e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "erasable_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 561730554d9SArtem B. Bityutskiy jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 562730554d9SArtem B. Bityutskiy jeb->unchecked_size, jeb->free_size); 563730554d9SArtem B. Bityutskiy } 564730554d9SArtem B. Bityutskiy } 565730554d9SArtem B. Bityutskiy } 566730554d9SArtem B. Bityutskiy 567730554d9SArtem B. Bityutskiy if (list_empty(&c->erasing_list)) { 56881e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "erasing_list: empty\n"); 569730554d9SArtem B. Bityutskiy } else { 570730554d9SArtem B. Bityutskiy struct list_head *this; 571730554d9SArtem B. Bityutskiy 572730554d9SArtem B. Bityutskiy list_for_each(this, &c->erasing_list) { 573730554d9SArtem B. Bityutskiy struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 574730554d9SArtem B. Bityutskiy 575730554d9SArtem B. Bityutskiy if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 57681e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "erasing_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 577730554d9SArtem B. Bityutskiy jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 578730554d9SArtem B. Bityutskiy jeb->unchecked_size, jeb->free_size); 579730554d9SArtem B. Bityutskiy } 580730554d9SArtem B. Bityutskiy } 581730554d9SArtem B. Bityutskiy } 582730554d9SArtem B. Bityutskiy 583730554d9SArtem B. Bityutskiy if (list_empty(&c->erase_pending_list)) { 58481e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "erase_pending_list: empty\n"); 585730554d9SArtem B. Bityutskiy } else { 586730554d9SArtem B. Bityutskiy struct list_head *this; 587730554d9SArtem B. Bityutskiy 588730554d9SArtem B. Bityutskiy list_for_each(this, &c->erase_pending_list) { 589730554d9SArtem B. Bityutskiy struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 590730554d9SArtem B. Bityutskiy 591730554d9SArtem B. Bityutskiy if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 59281e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "erase_pending_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 593730554d9SArtem B. Bityutskiy jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 594730554d9SArtem B. Bityutskiy jeb->unchecked_size, jeb->free_size); 595730554d9SArtem B. Bityutskiy } 596730554d9SArtem B. Bityutskiy } 597730554d9SArtem B. Bityutskiy } 598730554d9SArtem B. Bityutskiy 599730554d9SArtem B. Bityutskiy if (list_empty(&c->erasable_pending_wbuf_list)) { 60081e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "erasable_pending_wbuf_list: empty\n"); 601730554d9SArtem B. Bityutskiy } else { 602730554d9SArtem B. Bityutskiy struct list_head *this; 603730554d9SArtem B. Bityutskiy 604730554d9SArtem B. Bityutskiy list_for_each(this, &c->erasable_pending_wbuf_list) { 605730554d9SArtem B. Bityutskiy struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 606730554d9SArtem B. Bityutskiy 607730554d9SArtem B. Bityutskiy if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 60881e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "erasable_pending_wbuf_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 609730554d9SArtem B. Bityutskiy jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 610730554d9SArtem B. Bityutskiy jeb->unchecked_size, jeb->free_size); 611730554d9SArtem B. Bityutskiy } 612730554d9SArtem B. Bityutskiy } 613730554d9SArtem B. Bityutskiy } 614730554d9SArtem B. Bityutskiy 615730554d9SArtem B. Bityutskiy if (list_empty(&c->free_list)) { 61681e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "free_list: empty\n"); 617730554d9SArtem B. Bityutskiy } else { 618730554d9SArtem B. Bityutskiy struct list_head *this; 619730554d9SArtem B. Bityutskiy 620730554d9SArtem B. Bityutskiy list_for_each(this, &c->free_list) { 621730554d9SArtem B. Bityutskiy struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 622730554d9SArtem B. Bityutskiy 623730554d9SArtem B. Bityutskiy if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 62481e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "free_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 625730554d9SArtem B. Bityutskiy jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 626730554d9SArtem B. Bityutskiy jeb->unchecked_size, jeb->free_size); 627730554d9SArtem B. Bityutskiy } 628730554d9SArtem B. Bityutskiy } 629730554d9SArtem B. Bityutskiy } 630730554d9SArtem B. Bityutskiy 631730554d9SArtem B. Bityutskiy if (list_empty(&c->bad_list)) { 63281e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "bad_list: empty\n"); 633730554d9SArtem B. Bityutskiy } else { 634730554d9SArtem B. Bityutskiy struct list_head *this; 635730554d9SArtem B. Bityutskiy 636730554d9SArtem B. Bityutskiy list_for_each(this, &c->bad_list) { 637730554d9SArtem B. Bityutskiy struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 638730554d9SArtem B. Bityutskiy 639730554d9SArtem B. Bityutskiy if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 64081e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "bad_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 641730554d9SArtem B. Bityutskiy jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 642730554d9SArtem B. Bityutskiy jeb->unchecked_size, jeb->free_size); 643730554d9SArtem B. Bityutskiy } 644730554d9SArtem B. Bityutskiy } 645730554d9SArtem B. Bityutskiy } 646730554d9SArtem B. Bityutskiy 647730554d9SArtem B. Bityutskiy if (list_empty(&c->bad_used_list)) { 64881e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "bad_used_list: empty\n"); 649730554d9SArtem B. Bityutskiy } else { 650730554d9SArtem B. Bityutskiy struct list_head *this; 651730554d9SArtem B. Bityutskiy 652730554d9SArtem B. Bityutskiy list_for_each(this, &c->bad_used_list) { 653730554d9SArtem B. Bityutskiy struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 654730554d9SArtem B. Bityutskiy 655730554d9SArtem B. Bityutskiy if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 65681e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "bad_used_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 657730554d9SArtem B. Bityutskiy jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 658730554d9SArtem B. Bityutskiy jeb->unchecked_size, jeb->free_size); 659730554d9SArtem B. Bityutskiy } 660730554d9SArtem B. Bityutskiy } 661730554d9SArtem B. Bityutskiy } 662730554d9SArtem B. Bityutskiy } 663730554d9SArtem B. Bityutskiy 664730554d9SArtem B. Bityutskiy void 665e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_fragtree(struct jffs2_inode_info *f) 666e0c8e42fSArtem B. Bityutskiy { 667ced22070SDavid Woodhouse mutex_lock(&f->sem); 668e0c8e42fSArtem B. Bityutskiy jffs2_dbg_dump_fragtree_nolock(f); 669ced22070SDavid Woodhouse mutex_unlock(&f->sem); 670e0c8e42fSArtem B. Bityutskiy } 671e0c8e42fSArtem B. Bityutskiy 672e0c8e42fSArtem B. Bityutskiy void 673e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_fragtree_nolock(struct jffs2_inode_info *f) 674730554d9SArtem B. Bityutskiy { 675730554d9SArtem B. Bityutskiy struct jffs2_node_frag *this = frag_first(&f->fragtree); 676730554d9SArtem B. Bityutskiy uint32_t lastofs = 0; 677730554d9SArtem B. Bityutskiy int buggy = 0; 678730554d9SArtem B. Bityutskiy 67981e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG_MSG_PREFIX " dump fragtree of ino #%u\n", f->inocache->ino); 680730554d9SArtem B. Bityutskiy while(this) { 681730554d9SArtem B. Bityutskiy if (this->node) 68281e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "frag %#04x-%#04x: %#08x(%d) on flash (*%p), left (%p), right (%p), parent (%p)\n", 683730554d9SArtem B. Bityutskiy this->ofs, this->ofs+this->size, ref_offset(this->node->raw), 684730554d9SArtem B. Bityutskiy ref_flags(this->node->raw), this, frag_left(this), frag_right(this), 685730554d9SArtem B. Bityutskiy frag_parent(this)); 686730554d9SArtem B. Bityutskiy else 68781e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "frag %#04x-%#04x: hole (*%p). left (%p), right (%p), parent (%p)\n", 688730554d9SArtem B. Bityutskiy this->ofs, this->ofs+this->size, this, frag_left(this), 689730554d9SArtem B. Bityutskiy frag_right(this), frag_parent(this)); 690730554d9SArtem B. Bityutskiy if (this->ofs != lastofs) 691730554d9SArtem B. Bityutskiy buggy = 1; 692730554d9SArtem B. Bityutskiy lastofs = this->ofs + this->size; 693730554d9SArtem B. Bityutskiy this = frag_next(this); 694730554d9SArtem B. Bityutskiy } 695730554d9SArtem B. Bityutskiy 696730554d9SArtem B. Bityutskiy if (f->metadata) 69781e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "metadata at 0x%08x\n", ref_offset(f->metadata->raw)); 698730554d9SArtem B. Bityutskiy 699730554d9SArtem B. Bityutskiy if (buggy) { 700e0c8e42fSArtem B. Bityutskiy JFFS2_ERROR("frag tree got a hole in it.\n"); 701730554d9SArtem B. Bityutskiy BUG(); 702730554d9SArtem B. Bityutskiy } 703730554d9SArtem B. Bityutskiy } 704730554d9SArtem B. Bityutskiy 705e0c8e42fSArtem B. Bityutskiy #define JFFS2_BUFDUMP_BYTES_PER_LINE 32 706730554d9SArtem B. Bityutskiy void 707e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_buffer(unsigned char *buf, int len, uint32_t offs) 708730554d9SArtem B. Bityutskiy { 709e0c8e42fSArtem B. Bityutskiy int skip; 710e0c8e42fSArtem B. Bityutskiy int i; 711e0c8e42fSArtem B. Bityutskiy 71281e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG_MSG_PREFIX " dump from offset %#08x to offset %#08x (%x bytes).\n", 713e0c8e42fSArtem B. Bityutskiy offs, offs + len, len); 714e0c8e42fSArtem B. Bityutskiy i = skip = offs % JFFS2_BUFDUMP_BYTES_PER_LINE; 715e0c8e42fSArtem B. Bityutskiy offs = offs & ~(JFFS2_BUFDUMP_BYTES_PER_LINE - 1); 716e0c8e42fSArtem B. Bityutskiy 717e0c8e42fSArtem B. Bityutskiy if (skip != 0) 71881e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "%#08x: ", offs); 719e0c8e42fSArtem B. Bityutskiy 720e0c8e42fSArtem B. Bityutskiy while (skip--) 721e0c8e42fSArtem B. Bityutskiy printk(" "); 722730554d9SArtem B. Bityutskiy 723730554d9SArtem B. Bityutskiy while (i < len) { 724e0c8e42fSArtem B. Bityutskiy if ((i % JFFS2_BUFDUMP_BYTES_PER_LINE) == 0 && i != len -1) { 725e0c8e42fSArtem B. Bityutskiy if (i != 0) 726e0c8e42fSArtem B. Bityutskiy printk("\n"); 727e0c8e42fSArtem B. Bityutskiy offs += JFFS2_BUFDUMP_BYTES_PER_LINE; 72881e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "%0#8x: ", offs); 729730554d9SArtem B. Bityutskiy } 730730554d9SArtem B. Bityutskiy 731e0c8e42fSArtem B. Bityutskiy printk("%02x ", buf[i]); 732e0c8e42fSArtem B. Bityutskiy 733e0c8e42fSArtem B. Bityutskiy i += 1; 734730554d9SArtem B. Bityutskiy } 735730554d9SArtem B. Bityutskiy 736e0c8e42fSArtem B. Bityutskiy printk("\n"); 737e0c8e42fSArtem B. Bityutskiy } 738e0c8e42fSArtem B. Bityutskiy 739e0c8e42fSArtem B. Bityutskiy /* 740e0c8e42fSArtem B. Bityutskiy * Dump a JFFS2 node. 741e0c8e42fSArtem B. Bityutskiy */ 742e0c8e42fSArtem B. Bityutskiy void 743e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_node(struct jffs2_sb_info *c, uint32_t ofs) 744e0c8e42fSArtem B. Bityutskiy { 745e0c8e42fSArtem B. Bityutskiy union jffs2_node_union node; 746e0c8e42fSArtem B. Bityutskiy int len = sizeof(union jffs2_node_union); 747e0c8e42fSArtem B. Bityutskiy size_t retlen; 748e0c8e42fSArtem B. Bityutskiy uint32_t crc; 749e0c8e42fSArtem B. Bityutskiy int ret; 750e0c8e42fSArtem B. Bityutskiy 75181e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG_MSG_PREFIX " dump node at offset %#08x.\n", ofs); 752e0c8e42fSArtem B. Bityutskiy 753e0c8e42fSArtem B. Bityutskiy ret = jffs2_flash_read(c, ofs, len, &retlen, (unsigned char *)&node); 754e0c8e42fSArtem B. Bityutskiy if (ret || (retlen != len)) { 755e0c8e42fSArtem B. Bityutskiy JFFS2_ERROR("read %d bytes failed or short. ret %d, retlen %zd.\n", 756e0c8e42fSArtem B. Bityutskiy len, ret, retlen); 757e0c8e42fSArtem B. Bityutskiy return; 758e0c8e42fSArtem B. Bityutskiy } 759e0c8e42fSArtem B. Bityutskiy 76081e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "magic:\t%#04x\n", je16_to_cpu(node.u.magic)); 76181e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "nodetype:\t%#04x\n", je16_to_cpu(node.u.nodetype)); 76281e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "totlen:\t%#08x\n", je32_to_cpu(node.u.totlen)); 76381e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "hdr_crc:\t%#08x\n", je32_to_cpu(node.u.hdr_crc)); 764e0c8e42fSArtem B. Bityutskiy 765e0c8e42fSArtem B. Bityutskiy crc = crc32(0, &node.u, sizeof(node.u) - 4); 766e0c8e42fSArtem B. Bityutskiy if (crc != je32_to_cpu(node.u.hdr_crc)) { 767e0c8e42fSArtem B. Bityutskiy JFFS2_ERROR("wrong common header CRC.\n"); 768e0c8e42fSArtem B. Bityutskiy return; 769e0c8e42fSArtem B. Bityutskiy } 770e0c8e42fSArtem B. Bityutskiy 771e0c8e42fSArtem B. Bityutskiy if (je16_to_cpu(node.u.magic) != JFFS2_MAGIC_BITMASK && 772e0c8e42fSArtem B. Bityutskiy je16_to_cpu(node.u.magic) != JFFS2_OLD_MAGIC_BITMASK) 773e0c8e42fSArtem B. Bityutskiy { 774e0c8e42fSArtem B. Bityutskiy JFFS2_ERROR("wrong node magic: %#04x instead of %#04x.\n", 775e0c8e42fSArtem B. Bityutskiy je16_to_cpu(node.u.magic), JFFS2_MAGIC_BITMASK); 776e0c8e42fSArtem B. Bityutskiy return; 777e0c8e42fSArtem B. Bityutskiy } 778e0c8e42fSArtem B. Bityutskiy 779e0c8e42fSArtem B. Bityutskiy switch(je16_to_cpu(node.u.nodetype)) { 780e0c8e42fSArtem B. Bityutskiy 781e0c8e42fSArtem B. Bityutskiy case JFFS2_NODETYPE_INODE: 782e0c8e42fSArtem B. Bityutskiy 78381e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "the node is inode node\n"); 78481e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "ino:\t%#08x\n", je32_to_cpu(node.i.ino)); 78581e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "version:\t%#08x\n", je32_to_cpu(node.i.version)); 78681e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "mode:\t%#08x\n", node.i.mode.m); 78781e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "uid:\t%#04x\n", je16_to_cpu(node.i.uid)); 78881e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "gid:\t%#04x\n", je16_to_cpu(node.i.gid)); 78981e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "isize:\t%#08x\n", je32_to_cpu(node.i.isize)); 79081e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "atime:\t%#08x\n", je32_to_cpu(node.i.atime)); 79181e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "mtime:\t%#08x\n", je32_to_cpu(node.i.mtime)); 79281e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "ctime:\t%#08x\n", je32_to_cpu(node.i.ctime)); 79381e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "offset:\t%#08x\n", je32_to_cpu(node.i.offset)); 79481e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "csize:\t%#08x\n", je32_to_cpu(node.i.csize)); 79581e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "dsize:\t%#08x\n", je32_to_cpu(node.i.dsize)); 79681e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "compr:\t%#02x\n", node.i.compr); 79781e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "usercompr:\t%#02x\n", node.i.usercompr); 79881e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "flags:\t%#04x\n", je16_to_cpu(node.i.flags)); 79981e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "data_crc:\t%#08x\n", je32_to_cpu(node.i.data_crc)); 80081e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "node_crc:\t%#08x\n", je32_to_cpu(node.i.node_crc)); 80181e39cf0SArtem B. Bityutskiy 802e0c8e42fSArtem B. Bityutskiy crc = crc32(0, &node.i, sizeof(node.i) - 8); 803e0c8e42fSArtem B. Bityutskiy if (crc != je32_to_cpu(node.i.node_crc)) { 804e0c8e42fSArtem B. Bityutskiy JFFS2_ERROR("wrong node header CRC.\n"); 805e0c8e42fSArtem B. Bityutskiy return; 806e0c8e42fSArtem B. Bityutskiy } 807e0c8e42fSArtem B. Bityutskiy break; 808e0c8e42fSArtem B. Bityutskiy 809e0c8e42fSArtem B. Bityutskiy case JFFS2_NODETYPE_DIRENT: 810e0c8e42fSArtem B. Bityutskiy 81181e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "the node is dirent node\n"); 81281e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "pino:\t%#08x\n", je32_to_cpu(node.d.pino)); 81381e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "version:\t%#08x\n", je32_to_cpu(node.d.version)); 81481e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "ino:\t%#08x\n", je32_to_cpu(node.d.ino)); 81581e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "mctime:\t%#08x\n", je32_to_cpu(node.d.mctime)); 81681e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "nsize:\t%#02x\n", node.d.nsize); 81781e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "type:\t%#02x\n", node.d.type); 81881e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "node_crc:\t%#08x\n", je32_to_cpu(node.d.node_crc)); 81981e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "name_crc:\t%#08x\n", je32_to_cpu(node.d.name_crc)); 820e0c8e42fSArtem B. Bityutskiy 821e0c8e42fSArtem B. Bityutskiy node.d.name[node.d.nsize] = '\0'; 82281e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "name:\t\"%s\"\n", node.d.name); 823e0c8e42fSArtem B. Bityutskiy 824e0c8e42fSArtem B. Bityutskiy crc = crc32(0, &node.d, sizeof(node.d) - 8); 825e0c8e42fSArtem B. Bityutskiy if (crc != je32_to_cpu(node.d.node_crc)) { 826e0c8e42fSArtem B. Bityutskiy JFFS2_ERROR("wrong node header CRC.\n"); 827e0c8e42fSArtem B. Bityutskiy return; 828e0c8e42fSArtem B. Bityutskiy } 829e0c8e42fSArtem B. Bityutskiy break; 830e0c8e42fSArtem B. Bityutskiy 831e0c8e42fSArtem B. Bityutskiy default: 83281e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "node type is unknown\n"); 833e0c8e42fSArtem B. Bityutskiy break; 834730554d9SArtem B. Bityutskiy } 835730554d9SArtem B. Bityutskiy } 836e0c8e42fSArtem B. Bityutskiy #endif /* JFFS2_DBG_DUMPS || JFFS2_DBG_PARANOIA_CHECKS */ 837