cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

debug.c (26245B)


      1/*
      2 * JFFS2 -- Journalling Flash File System, Version 2.
      3 *
      4 * Copyright © 2001-2007 Red Hat, Inc.
      5 * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org>
      6 *
      7 * Created by David Woodhouse <dwmw2@infradead.org>
      8 *
      9 * For licensing information, see the file 'LICENCE' in this directory.
     10 *
     11 */
     12
     13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     14
     15#include <linux/kernel.h>
     16#include <linux/types.h>
     17#include <linux/pagemap.h>
     18#include <linux/crc32.h>
     19#include <linux/jffs2.h>
     20#include <linux/mtd/mtd.h>
     21#include <linux/slab.h>
     22#include "nodelist.h"
     23#include "debug.h"
     24
     25#ifdef JFFS2_DBG_SANITY_CHECKS
     26
     27void
     28__jffs2_dbg_acct_sanity_check_nolock(struct jffs2_sb_info *c,
     29				     struct jffs2_eraseblock *jeb)
     30{
     31	if (unlikely(jeb && jeb->used_size + jeb->dirty_size +
     32			jeb->free_size + jeb->wasted_size +
     33			jeb->unchecked_size != c->sector_size)) {
     34		JFFS2_ERROR("eeep, space accounting for block at 0x%08x is screwed.\n", jeb->offset);
     35		JFFS2_ERROR("free %#08x + dirty %#08x + used %#08x + wasted %#08x + unchecked %#08x != total %#08x.\n",
     36			jeb->free_size, jeb->dirty_size, jeb->used_size,
     37			jeb->wasted_size, jeb->unchecked_size, c->sector_size);
     38		BUG();
     39	}
     40
     41	if (unlikely(c->used_size + c->dirty_size + c->free_size + c->erasing_size + c->bad_size
     42				+ c->wasted_size + c->unchecked_size != c->flash_size)) {
     43		JFFS2_ERROR("eeep, space accounting superblock info is screwed.\n");
     44		JFFS2_ERROR("free %#08x + dirty %#08x + used %#08x + erasing %#08x + bad %#08x + wasted %#08x + unchecked %#08x != total %#08x.\n",
     45			c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size,
     46			c->wasted_size, c->unchecked_size, c->flash_size);
     47		BUG();
     48	}
     49}
     50
     51void
     52__jffs2_dbg_acct_sanity_check(struct jffs2_sb_info *c,
     53			      struct jffs2_eraseblock *jeb)
     54{
     55	spin_lock(&c->erase_completion_lock);
     56	jffs2_dbg_acct_sanity_check_nolock(c, jeb);
     57	spin_unlock(&c->erase_completion_lock);
     58}
     59
     60#endif /* JFFS2_DBG_SANITY_CHECKS */
     61
     62#ifdef JFFS2_DBG_PARANOIA_CHECKS
     63/*
     64 * Check the fragtree.
     65 */
     66void
     67__jffs2_dbg_fragtree_paranoia_check(struct jffs2_inode_info *f)
     68{
     69	mutex_lock(&f->sem);
     70	__jffs2_dbg_fragtree_paranoia_check_nolock(f);
     71	mutex_unlock(&f->sem);
     72}
     73
     74void
     75__jffs2_dbg_fragtree_paranoia_check_nolock(struct jffs2_inode_info *f)
     76{
     77	struct jffs2_node_frag *frag;
     78	int bitched = 0;
     79
     80	for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) {
     81		struct jffs2_full_dnode *fn = frag->node;
     82
     83		if (!fn || !fn->raw)
     84			continue;
     85
     86		if (ref_flags(fn->raw) == REF_PRISTINE) {
     87			if (fn->frags > 1) {
     88				JFFS2_ERROR("REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2.\n",
     89					ref_offset(fn->raw), fn->frags);
     90				bitched = 1;
     91			}
     92
     93			/* A hole node which isn't multi-page should be garbage-collected
     94			   and merged anyway, so we just check for the frag size here,
     95			   rather than mucking around with actually reading the node
     96			   and checking the compression type, which is the real way
     97			   to tell a hole node. */
     98			if (frag->ofs & (PAGE_SIZE-1) && frag_prev(frag)
     99					&& frag_prev(frag)->size < PAGE_SIZE && frag_prev(frag)->node) {
    100				JFFS2_ERROR("REF_PRISTINE node at 0x%08x had a previous non-hole frag in the same page. Tell dwmw2.\n",
    101					ref_offset(fn->raw));
    102				bitched = 1;
    103			}
    104
    105			if ((frag->ofs+frag->size) & (PAGE_SIZE-1) && frag_next(frag)
    106					&& frag_next(frag)->size < PAGE_SIZE && frag_next(frag)->node) {
    107				JFFS2_ERROR("REF_PRISTINE node at 0x%08x (%08x-%08x) had a following non-hole frag in the same page. Tell dwmw2.\n",
    108				       ref_offset(fn->raw), frag->ofs, frag->ofs+frag->size);
    109				bitched = 1;
    110			}
    111		}
    112	}
    113
    114	if (bitched) {
    115		JFFS2_ERROR("fragtree is corrupted.\n");
    116		__jffs2_dbg_dump_fragtree_nolock(f);
    117		BUG();
    118	}
    119}
    120
    121/*
    122 * Check if the flash contains all 0xFF before we start writing.
    123 */
    124void
    125__jffs2_dbg_prewrite_paranoia_check(struct jffs2_sb_info *c,
    126				    uint32_t ofs, int len)
    127{
    128	size_t retlen;
    129	int ret, i;
    130	unsigned char *buf;
    131
    132	buf = kmalloc(len, GFP_KERNEL);
    133	if (!buf)
    134		return;
    135
    136	ret = jffs2_flash_read(c, ofs, len, &retlen, buf);
    137	if (ret || (retlen != len)) {
    138		JFFS2_WARNING("read %d bytes failed or short. ret %d, retlen %zd.\n",
    139				len, ret, retlen);
    140		kfree(buf);
    141		return;
    142	}
    143
    144	ret = 0;
    145	for (i = 0; i < len; i++)
    146		if (buf[i] != 0xff)
    147			ret = 1;
    148
    149	if (ret) {
    150		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",
    151			ofs, ofs + i);
    152		__jffs2_dbg_dump_buffer(buf, len, ofs);
    153		kfree(buf);
    154		BUG();
    155	}
    156
    157	kfree(buf);
    158}
    159
    160void __jffs2_dbg_superblock_counts(struct jffs2_sb_info *c)
    161{
    162	struct jffs2_eraseblock *jeb;
    163	uint32_t free = 0, dirty = 0, used = 0, wasted = 0,
    164		erasing = 0, bad = 0, unchecked = 0;
    165	int nr_counted = 0;
    166	int dump = 0;
    167
    168	if (c->gcblock) {
    169		nr_counted++;
    170		free += c->gcblock->free_size;
    171		dirty += c->gcblock->dirty_size;
    172		used += c->gcblock->used_size;
    173		wasted += c->gcblock->wasted_size;
    174		unchecked += c->gcblock->unchecked_size;
    175	}
    176	if (c->nextblock) {
    177		nr_counted++;
    178		free += c->nextblock->free_size;
    179		dirty += c->nextblock->dirty_size;
    180		used += c->nextblock->used_size;
    181		wasted += c->nextblock->wasted_size;
    182		unchecked += c->nextblock->unchecked_size;
    183	}
    184	list_for_each_entry(jeb, &c->clean_list, list) {
    185		nr_counted++;
    186		free += jeb->free_size;
    187		dirty += jeb->dirty_size;
    188		used += jeb->used_size;
    189		wasted += jeb->wasted_size;
    190		unchecked += jeb->unchecked_size;
    191	}
    192	list_for_each_entry(jeb, &c->very_dirty_list, list) {
    193		nr_counted++;
    194		free += jeb->free_size;
    195		dirty += jeb->dirty_size;
    196		used += jeb->used_size;
    197		wasted += jeb->wasted_size;
    198		unchecked += jeb->unchecked_size;
    199	}
    200	list_for_each_entry(jeb, &c->dirty_list, list) {
    201		nr_counted++;
    202		free += jeb->free_size;
    203		dirty += jeb->dirty_size;
    204		used += jeb->used_size;
    205		wasted += jeb->wasted_size;
    206		unchecked += jeb->unchecked_size;
    207	}
    208	list_for_each_entry(jeb, &c->erasable_list, list) {
    209		nr_counted++;
    210		free += jeb->free_size;
    211		dirty += jeb->dirty_size;
    212		used += jeb->used_size;
    213		wasted += jeb->wasted_size;
    214		unchecked += jeb->unchecked_size;
    215	}
    216	list_for_each_entry(jeb, &c->erasable_pending_wbuf_list, list) {
    217		nr_counted++;
    218		free += jeb->free_size;
    219		dirty += jeb->dirty_size;
    220		used += jeb->used_size;
    221		wasted += jeb->wasted_size;
    222		unchecked += jeb->unchecked_size;
    223	}
    224	list_for_each_entry(jeb, &c->erase_pending_list, list) {
    225		nr_counted++;
    226		free += jeb->free_size;
    227		dirty += jeb->dirty_size;
    228		used += jeb->used_size;
    229		wasted += jeb->wasted_size;
    230		unchecked += jeb->unchecked_size;
    231	}
    232	list_for_each_entry(jeb, &c->free_list, list) {
    233		nr_counted++;
    234		free += jeb->free_size;
    235		dirty += jeb->dirty_size;
    236		used += jeb->used_size;
    237		wasted += jeb->wasted_size;
    238		unchecked += jeb->unchecked_size;
    239	}
    240	list_for_each_entry(jeb, &c->bad_used_list, list) {
    241		nr_counted++;
    242		free += jeb->free_size;
    243		dirty += jeb->dirty_size;
    244		used += jeb->used_size;
    245		wasted += jeb->wasted_size;
    246		unchecked += jeb->unchecked_size;
    247	}
    248
    249	list_for_each_entry(jeb, &c->erasing_list, list) {
    250		nr_counted++;
    251		erasing += c->sector_size;
    252	}
    253	list_for_each_entry(jeb, &c->erase_checking_list, list) {
    254		nr_counted++;
    255		erasing += c->sector_size;
    256	}
    257	list_for_each_entry(jeb, &c->erase_complete_list, list) {
    258		nr_counted++;
    259		erasing += c->sector_size;
    260	}
    261	list_for_each_entry(jeb, &c->bad_list, list) {
    262		nr_counted++;
    263		bad += c->sector_size;
    264	}
    265
    266#define check(sz)							\
    267do {									\
    268	if (sz != c->sz##_size) {					\
    269		pr_warn("%s_size mismatch counted 0x%x, c->%s_size 0x%x\n", \
    270			#sz, sz, #sz, c->sz##_size);			\
    271		dump = 1;						\
    272	}								\
    273} while (0)
    274
    275	check(free);
    276	check(dirty);
    277	check(used);
    278	check(wasted);
    279	check(unchecked);
    280	check(bad);
    281	check(erasing);
    282
    283#undef check
    284
    285	if (nr_counted != c->nr_blocks) {
    286		pr_warn("%s counted only 0x%x blocks of 0x%x. Where are the others?\n",
    287			__func__, nr_counted, c->nr_blocks);
    288		dump = 1;
    289	}
    290
    291	if (dump) {
    292		__jffs2_dbg_dump_block_lists_nolock(c);
    293		BUG();
    294	}
    295}
    296
    297/*
    298 * Check the space accounting and node_ref list correctness for the JFFS2 erasable block 'jeb'.
    299 */
    300void
    301__jffs2_dbg_acct_paranoia_check(struct jffs2_sb_info *c,
    302				struct jffs2_eraseblock *jeb)
    303{
    304	spin_lock(&c->erase_completion_lock);
    305	__jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
    306	spin_unlock(&c->erase_completion_lock);
    307}
    308
    309void
    310__jffs2_dbg_acct_paranoia_check_nolock(struct jffs2_sb_info *c,
    311				       struct jffs2_eraseblock *jeb)
    312{
    313	uint32_t my_used_size = 0;
    314	uint32_t my_unchecked_size = 0;
    315	uint32_t my_dirty_size = 0;
    316	struct jffs2_raw_node_ref *ref2 = jeb->first_node;
    317
    318	while (ref2) {
    319		uint32_t totlen = ref_totlen(c, jeb, ref2);
    320
    321		if (ref_offset(ref2) < jeb->offset ||
    322				ref_offset(ref2) > jeb->offset + c->sector_size) {
    323			JFFS2_ERROR("node_ref %#08x shouldn't be in block at %#08x.\n",
    324				ref_offset(ref2), jeb->offset);
    325			goto error;
    326
    327		}
    328		if (ref_flags(ref2) == REF_UNCHECKED)
    329			my_unchecked_size += totlen;
    330		else if (!ref_obsolete(ref2))
    331			my_used_size += totlen;
    332		else
    333			my_dirty_size += totlen;
    334
    335		if ((!ref_next(ref2)) != (ref2 == jeb->last_node)) {
    336			JFFS2_ERROR("node_ref for node at %#08x (mem %p) has next at %#08x (mem %p), last_node is at %#08x (mem %p).\n",
    337				    ref_offset(ref2), ref2, ref_offset(ref_next(ref2)), ref_next(ref2),
    338				    ref_offset(jeb->last_node), jeb->last_node);
    339			goto error;
    340		}
    341		ref2 = ref_next(ref2);
    342	}
    343
    344	if (my_used_size != jeb->used_size) {
    345		JFFS2_ERROR("Calculated used size %#08x != stored used size %#08x.\n",
    346			my_used_size, jeb->used_size);
    347		goto error;
    348	}
    349
    350	if (my_unchecked_size != jeb->unchecked_size) {
    351		JFFS2_ERROR("Calculated unchecked size %#08x != stored unchecked size %#08x.\n",
    352			my_unchecked_size, jeb->unchecked_size);
    353		goto error;
    354	}
    355
    356#if 0
    357	/* This should work when we implement ref->__totlen elemination */
    358	if (my_dirty_size != jeb->dirty_size + jeb->wasted_size) {
    359		JFFS2_ERROR("Calculated dirty+wasted size %#08x != stored dirty + wasted size %#08x\n",
    360			my_dirty_size, jeb->dirty_size + jeb->wasted_size);
    361		goto error;
    362	}
    363
    364	if (jeb->free_size == 0
    365		&& my_used_size + my_unchecked_size + my_dirty_size != c->sector_size) {
    366		JFFS2_ERROR("The sum of all nodes in block (%#x) != size of block (%#x)\n",
    367			my_used_size + my_unchecked_size + my_dirty_size,
    368			c->sector_size);
    369		goto error;
    370	}
    371#endif
    372
    373	if (!(c->flags & (JFFS2_SB_FLAG_BUILDING|JFFS2_SB_FLAG_SCANNING)))
    374		__jffs2_dbg_superblock_counts(c);
    375
    376	return;
    377
    378error:
    379	__jffs2_dbg_dump_node_refs_nolock(c, jeb);
    380	__jffs2_dbg_dump_jeb_nolock(jeb);
    381	__jffs2_dbg_dump_block_lists_nolock(c);
    382	BUG();
    383
    384}
    385#endif /* JFFS2_DBG_PARANOIA_CHECKS */
    386
    387#if defined(JFFS2_DBG_DUMPS) || defined(JFFS2_DBG_PARANOIA_CHECKS)
    388/*
    389 * Dump the node_refs of the 'jeb' JFFS2 eraseblock.
    390 */
    391void
    392__jffs2_dbg_dump_node_refs(struct jffs2_sb_info *c,
    393			   struct jffs2_eraseblock *jeb)
    394{
    395	spin_lock(&c->erase_completion_lock);
    396	__jffs2_dbg_dump_node_refs_nolock(c, jeb);
    397	spin_unlock(&c->erase_completion_lock);
    398}
    399
    400void
    401__jffs2_dbg_dump_node_refs_nolock(struct jffs2_sb_info *c,
    402				  struct jffs2_eraseblock *jeb)
    403{
    404	struct jffs2_raw_node_ref *ref;
    405	int i = 0;
    406
    407	printk(JFFS2_DBG_MSG_PREFIX " Dump node_refs of the eraseblock %#08x\n", jeb->offset);
    408	if (!jeb->first_node) {
    409		printk(JFFS2_DBG_MSG_PREFIX " no nodes in the eraseblock %#08x\n", jeb->offset);
    410		return;
    411	}
    412
    413	printk(JFFS2_DBG);
    414	for (ref = jeb->first_node; ; ref = ref_next(ref)) {
    415		printk("%#08x", ref_offset(ref));
    416#ifdef TEST_TOTLEN
    417		printk("(%x)", ref->__totlen);
    418#endif
    419		if (ref_next(ref))
    420			printk("->");
    421		else
    422			break;
    423		if (++i == 4) {
    424			i = 0;
    425			printk("\n" JFFS2_DBG);
    426		}
    427	}
    428	printk("\n");
    429}
    430
    431/*
    432 * Dump an eraseblock's space accounting.
    433 */
    434void
    435__jffs2_dbg_dump_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
    436{
    437	spin_lock(&c->erase_completion_lock);
    438	__jffs2_dbg_dump_jeb_nolock(jeb);
    439	spin_unlock(&c->erase_completion_lock);
    440}
    441
    442void
    443__jffs2_dbg_dump_jeb_nolock(struct jffs2_eraseblock *jeb)
    444{
    445	if (!jeb)
    446		return;
    447
    448	printk(JFFS2_DBG_MSG_PREFIX " dump space accounting for the eraseblock at %#08x:\n",
    449			jeb->offset);
    450
    451	printk(JFFS2_DBG "used_size: %#08x\n",		jeb->used_size);
    452	printk(JFFS2_DBG "dirty_size: %#08x\n",		jeb->dirty_size);
    453	printk(JFFS2_DBG "wasted_size: %#08x\n",	jeb->wasted_size);
    454	printk(JFFS2_DBG "unchecked_size: %#08x\n",	jeb->unchecked_size);
    455	printk(JFFS2_DBG "free_size: %#08x\n",		jeb->free_size);
    456}
    457
    458void
    459__jffs2_dbg_dump_block_lists(struct jffs2_sb_info *c)
    460{
    461	spin_lock(&c->erase_completion_lock);
    462	__jffs2_dbg_dump_block_lists_nolock(c);
    463	spin_unlock(&c->erase_completion_lock);
    464}
    465
    466void
    467__jffs2_dbg_dump_block_lists_nolock(struct jffs2_sb_info *c)
    468{
    469	printk(JFFS2_DBG_MSG_PREFIX " dump JFFS2 blocks lists:\n");
    470
    471	printk(JFFS2_DBG "flash_size: %#08x\n",		c->flash_size);
    472	printk(JFFS2_DBG "used_size: %#08x\n",		c->used_size);
    473	printk(JFFS2_DBG "dirty_size: %#08x\n",		c->dirty_size);
    474	printk(JFFS2_DBG "wasted_size: %#08x\n",	c->wasted_size);
    475	printk(JFFS2_DBG "unchecked_size: %#08x\n",	c->unchecked_size);
    476	printk(JFFS2_DBG "free_size: %#08x\n",		c->free_size);
    477	printk(JFFS2_DBG "erasing_size: %#08x\n",	c->erasing_size);
    478	printk(JFFS2_DBG "bad_size: %#08x\n",		c->bad_size);
    479	printk(JFFS2_DBG "sector_size: %#08x\n",	c->sector_size);
    480	printk(JFFS2_DBG "jffs2_reserved_blocks size: %#08x\n",
    481				c->sector_size * c->resv_blocks_write);
    482
    483	if (c->nextblock)
    484		printk(JFFS2_DBG "nextblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
    485			c->nextblock->offset, c->nextblock->used_size,
    486			c->nextblock->dirty_size, c->nextblock->wasted_size,
    487			c->nextblock->unchecked_size, c->nextblock->free_size);
    488	else
    489		printk(JFFS2_DBG "nextblock: NULL\n");
    490
    491	if (c->gcblock)
    492		printk(JFFS2_DBG "gcblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
    493			c->gcblock->offset, c->gcblock->used_size, c->gcblock->dirty_size,
    494			c->gcblock->wasted_size, c->gcblock->unchecked_size, c->gcblock->free_size);
    495	else
    496		printk(JFFS2_DBG "gcblock: NULL\n");
    497
    498	if (list_empty(&c->clean_list)) {
    499		printk(JFFS2_DBG "clean_list: empty\n");
    500	} else {
    501		struct list_head *this;
    502		int numblocks = 0;
    503		uint32_t dirty = 0;
    504
    505		list_for_each(this, &c->clean_list) {
    506			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
    507			numblocks ++;
    508			dirty += jeb->wasted_size;
    509			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
    510				printk(JFFS2_DBG "clean_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
    511					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
    512					jeb->unchecked_size, jeb->free_size);
    513			}
    514		}
    515
    516		printk (JFFS2_DBG "Contains %d blocks with total wasted size %u, average wasted size: %u\n",
    517			numblocks, dirty, dirty / numblocks);
    518	}
    519
    520	if (list_empty(&c->very_dirty_list)) {
    521		printk(JFFS2_DBG "very_dirty_list: empty\n");
    522	} else {
    523		struct list_head *this;
    524		int numblocks = 0;
    525		uint32_t dirty = 0;
    526
    527		list_for_each(this, &c->very_dirty_list) {
    528			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
    529
    530			numblocks ++;
    531			dirty += jeb->dirty_size;
    532			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
    533				printk(JFFS2_DBG "very_dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
    534					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
    535					jeb->unchecked_size, jeb->free_size);
    536			}
    537		}
    538
    539		printk (JFFS2_DBG "Contains %d blocks with total dirty size %u, average dirty size: %u\n",
    540			numblocks, dirty, dirty / numblocks);
    541	}
    542
    543	if (list_empty(&c->dirty_list)) {
    544		printk(JFFS2_DBG "dirty_list: empty\n");
    545	} else {
    546		struct list_head *this;
    547		int numblocks = 0;
    548		uint32_t dirty = 0;
    549
    550		list_for_each(this, &c->dirty_list) {
    551			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
    552
    553			numblocks ++;
    554			dirty += jeb->dirty_size;
    555			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
    556				printk(JFFS2_DBG "dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
    557					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
    558					jeb->unchecked_size, jeb->free_size);
    559			}
    560		}
    561
    562		printk (JFFS2_DBG "contains %d blocks with total dirty size %u, average dirty size: %u\n",
    563			numblocks, dirty, dirty / numblocks);
    564	}
    565
    566	if (list_empty(&c->erasable_list)) {
    567		printk(JFFS2_DBG "erasable_list: empty\n");
    568	} else {
    569		struct list_head *this;
    570
    571		list_for_each(this, &c->erasable_list) {
    572			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
    573
    574			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
    575				printk(JFFS2_DBG "erasable_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
    576					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
    577					jeb->unchecked_size, jeb->free_size);
    578			}
    579		}
    580	}
    581
    582	if (list_empty(&c->erasing_list)) {
    583		printk(JFFS2_DBG "erasing_list: empty\n");
    584	} else {
    585		struct list_head *this;
    586
    587		list_for_each(this, &c->erasing_list) {
    588			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
    589
    590			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
    591				printk(JFFS2_DBG "erasing_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
    592					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
    593					jeb->unchecked_size, jeb->free_size);
    594			}
    595		}
    596	}
    597	if (list_empty(&c->erase_checking_list)) {
    598		printk(JFFS2_DBG "erase_checking_list: empty\n");
    599	} else {
    600		struct list_head *this;
    601
    602		list_for_each(this, &c->erase_checking_list) {
    603			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
    604
    605			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
    606				printk(JFFS2_DBG "erase_checking_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
    607					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
    608					jeb->unchecked_size, jeb->free_size);
    609			}
    610		}
    611	}
    612
    613	if (list_empty(&c->erase_pending_list)) {
    614		printk(JFFS2_DBG "erase_pending_list: empty\n");
    615	} else {
    616		struct list_head *this;
    617
    618		list_for_each(this, &c->erase_pending_list) {
    619			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
    620
    621			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
    622				printk(JFFS2_DBG "erase_pending_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
    623					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
    624					jeb->unchecked_size, jeb->free_size);
    625			}
    626		}
    627	}
    628
    629	if (list_empty(&c->erasable_pending_wbuf_list)) {
    630		printk(JFFS2_DBG "erasable_pending_wbuf_list: empty\n");
    631	} else {
    632		struct list_head *this;
    633
    634		list_for_each(this, &c->erasable_pending_wbuf_list) {
    635			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
    636
    637			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
    638				printk(JFFS2_DBG "erasable_pending_wbuf_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
    639					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
    640					jeb->unchecked_size, jeb->free_size);
    641			}
    642		}
    643	}
    644
    645	if (list_empty(&c->free_list)) {
    646		printk(JFFS2_DBG "free_list: empty\n");
    647	} else {
    648		struct list_head *this;
    649
    650		list_for_each(this, &c->free_list) {
    651			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
    652
    653			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
    654				printk(JFFS2_DBG "free_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
    655					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
    656					jeb->unchecked_size, jeb->free_size);
    657			}
    658		}
    659	}
    660
    661	if (list_empty(&c->bad_list)) {
    662		printk(JFFS2_DBG "bad_list: empty\n");
    663	} else {
    664		struct list_head *this;
    665
    666		list_for_each(this, &c->bad_list) {
    667			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
    668
    669			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
    670				printk(JFFS2_DBG "bad_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
    671					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
    672					jeb->unchecked_size, jeb->free_size);
    673			}
    674		}
    675	}
    676
    677	if (list_empty(&c->bad_used_list)) {
    678		printk(JFFS2_DBG "bad_used_list: empty\n");
    679	} else {
    680		struct list_head *this;
    681
    682		list_for_each(this, &c->bad_used_list) {
    683			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
    684
    685			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
    686				printk(JFFS2_DBG "bad_used_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
    687					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
    688					jeb->unchecked_size, jeb->free_size);
    689			}
    690		}
    691	}
    692}
    693
    694void
    695__jffs2_dbg_dump_fragtree(struct jffs2_inode_info *f)
    696{
    697	mutex_lock(&f->sem);
    698	jffs2_dbg_dump_fragtree_nolock(f);
    699	mutex_unlock(&f->sem);
    700}
    701
    702void
    703__jffs2_dbg_dump_fragtree_nolock(struct jffs2_inode_info *f)
    704{
    705	struct jffs2_node_frag *this = frag_first(&f->fragtree);
    706	uint32_t lastofs = 0;
    707	int buggy = 0;
    708
    709	printk(JFFS2_DBG_MSG_PREFIX " dump fragtree of ino #%u\n", f->inocache->ino);
    710	while(this) {
    711		if (this->node)
    712			printk(JFFS2_DBG "frag %#04x-%#04x: %#08x(%d) on flash (*%p), left (%p), right (%p), parent (%p)\n",
    713				this->ofs, this->ofs+this->size, ref_offset(this->node->raw),
    714				ref_flags(this->node->raw), this, frag_left(this), frag_right(this),
    715				frag_parent(this));
    716		else
    717			printk(JFFS2_DBG "frag %#04x-%#04x: hole (*%p). left (%p), right (%p), parent (%p)\n",
    718				this->ofs, this->ofs+this->size, this, frag_left(this),
    719				frag_right(this), frag_parent(this));
    720		if (this->ofs != lastofs)
    721			buggy = 1;
    722		lastofs = this->ofs + this->size;
    723		this = frag_next(this);
    724	}
    725
    726	if (f->metadata)
    727		printk(JFFS2_DBG "metadata at 0x%08x\n", ref_offset(f->metadata->raw));
    728
    729	if (buggy) {
    730		JFFS2_ERROR("frag tree got a hole in it.\n");
    731		BUG();
    732	}
    733}
    734
    735#define JFFS2_BUFDUMP_BYTES_PER_LINE	32
    736void
    737__jffs2_dbg_dump_buffer(unsigned char *buf, int len, uint32_t offs)
    738{
    739	int skip;
    740	int i;
    741
    742	printk(JFFS2_DBG_MSG_PREFIX " dump from offset %#08x to offset %#08x (%x bytes).\n",
    743		offs, offs + len, len);
    744	i = skip = offs % JFFS2_BUFDUMP_BYTES_PER_LINE;
    745	offs = offs & ~(JFFS2_BUFDUMP_BYTES_PER_LINE - 1);
    746
    747	if (skip != 0)
    748		printk(JFFS2_DBG "%#08x: ", offs);
    749
    750	while (skip--)
    751		printk("   ");
    752
    753	while (i < len) {
    754		if ((i % JFFS2_BUFDUMP_BYTES_PER_LINE) == 0 && i != len -1) {
    755			if (i != 0)
    756				printk("\n");
    757			offs += JFFS2_BUFDUMP_BYTES_PER_LINE;
    758			printk(JFFS2_DBG "%0#8x: ", offs);
    759		}
    760
    761		printk("%02x ", buf[i]);
    762
    763		i += 1;
    764	}
    765
    766	printk("\n");
    767}
    768
    769/*
    770 * Dump a JFFS2 node.
    771 */
    772void
    773__jffs2_dbg_dump_node(struct jffs2_sb_info *c, uint32_t ofs)
    774{
    775	union jffs2_node_union node;
    776	int len = sizeof(union jffs2_node_union);
    777	size_t retlen;
    778	uint32_t crc;
    779	int ret;
    780
    781	printk(JFFS2_DBG_MSG_PREFIX " dump node at offset %#08x.\n", ofs);
    782
    783	ret = jffs2_flash_read(c, ofs, len, &retlen, (unsigned char *)&node);
    784	if (ret || (retlen != len)) {
    785		JFFS2_ERROR("read %d bytes failed or short. ret %d, retlen %zd.\n",
    786			len, ret, retlen);
    787		return;
    788	}
    789
    790	printk(JFFS2_DBG "magic:\t%#04x\n", je16_to_cpu(node.u.magic));
    791	printk(JFFS2_DBG "nodetype:\t%#04x\n", je16_to_cpu(node.u.nodetype));
    792	printk(JFFS2_DBG "totlen:\t%#08x\n", je32_to_cpu(node.u.totlen));
    793	printk(JFFS2_DBG "hdr_crc:\t%#08x\n", je32_to_cpu(node.u.hdr_crc));
    794
    795	crc = crc32(0, &node.u, sizeof(node.u) - 4);
    796	if (crc != je32_to_cpu(node.u.hdr_crc)) {
    797		JFFS2_ERROR("wrong common header CRC.\n");
    798		return;
    799	}
    800
    801	if (je16_to_cpu(node.u.magic) != JFFS2_MAGIC_BITMASK &&
    802		je16_to_cpu(node.u.magic) != JFFS2_OLD_MAGIC_BITMASK)
    803	{
    804		JFFS2_ERROR("wrong node magic: %#04x instead of %#04x.\n",
    805			je16_to_cpu(node.u.magic), JFFS2_MAGIC_BITMASK);
    806		return;
    807	}
    808
    809	switch(je16_to_cpu(node.u.nodetype)) {
    810
    811	case JFFS2_NODETYPE_INODE:
    812
    813		printk(JFFS2_DBG "the node is inode node\n");
    814		printk(JFFS2_DBG "ino:\t%#08x\n", je32_to_cpu(node.i.ino));
    815		printk(JFFS2_DBG "version:\t%#08x\n", je32_to_cpu(node.i.version));
    816		printk(JFFS2_DBG "mode:\t%#08x\n", node.i.mode.m);
    817		printk(JFFS2_DBG "uid:\t%#04x\n", je16_to_cpu(node.i.uid));
    818		printk(JFFS2_DBG "gid:\t%#04x\n", je16_to_cpu(node.i.gid));
    819		printk(JFFS2_DBG "isize:\t%#08x\n", je32_to_cpu(node.i.isize));
    820		printk(JFFS2_DBG "atime:\t%#08x\n", je32_to_cpu(node.i.atime));
    821		printk(JFFS2_DBG "mtime:\t%#08x\n", je32_to_cpu(node.i.mtime));
    822		printk(JFFS2_DBG "ctime:\t%#08x\n", je32_to_cpu(node.i.ctime));
    823		printk(JFFS2_DBG "offset:\t%#08x\n", je32_to_cpu(node.i.offset));
    824		printk(JFFS2_DBG "csize:\t%#08x\n", je32_to_cpu(node.i.csize));
    825		printk(JFFS2_DBG "dsize:\t%#08x\n", je32_to_cpu(node.i.dsize));
    826		printk(JFFS2_DBG "compr:\t%#02x\n", node.i.compr);
    827		printk(JFFS2_DBG "usercompr:\t%#02x\n", node.i.usercompr);
    828		printk(JFFS2_DBG "flags:\t%#04x\n", je16_to_cpu(node.i.flags));
    829		printk(JFFS2_DBG "data_crc:\t%#08x\n", je32_to_cpu(node.i.data_crc));
    830		printk(JFFS2_DBG "node_crc:\t%#08x\n", je32_to_cpu(node.i.node_crc));
    831
    832		crc = crc32(0, &node.i, sizeof(node.i) - 8);
    833		if (crc != je32_to_cpu(node.i.node_crc)) {
    834			JFFS2_ERROR("wrong node header CRC.\n");
    835			return;
    836		}
    837		break;
    838
    839	case JFFS2_NODETYPE_DIRENT:
    840
    841		printk(JFFS2_DBG "the node is dirent node\n");
    842		printk(JFFS2_DBG "pino:\t%#08x\n", je32_to_cpu(node.d.pino));
    843		printk(JFFS2_DBG "version:\t%#08x\n", je32_to_cpu(node.d.version));
    844		printk(JFFS2_DBG "ino:\t%#08x\n", je32_to_cpu(node.d.ino));
    845		printk(JFFS2_DBG "mctime:\t%#08x\n", je32_to_cpu(node.d.mctime));
    846		printk(JFFS2_DBG "nsize:\t%#02x\n", node.d.nsize);
    847		printk(JFFS2_DBG "type:\t%#02x\n", node.d.type);
    848		printk(JFFS2_DBG "node_crc:\t%#08x\n", je32_to_cpu(node.d.node_crc));
    849		printk(JFFS2_DBG "name_crc:\t%#08x\n", je32_to_cpu(node.d.name_crc));
    850
    851		node.d.name[node.d.nsize] = '\0';
    852		printk(JFFS2_DBG "name:\t\"%s\"\n", node.d.name);
    853
    854		crc = crc32(0, &node.d, sizeof(node.d) - 8);
    855		if (crc != je32_to_cpu(node.d.node_crc)) {
    856			JFFS2_ERROR("wrong node header CRC.\n");
    857			return;
    858		}
    859		break;
    860
    861	default:
    862		printk(JFFS2_DBG "node type is unknown\n");
    863		break;
    864	}
    865}
    866#endif /* JFFS2_DBG_DUMPS || JFFS2_DBG_PARANOIA_CHECKS */