162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * JFFS2 -- Journalling Flash File System, Version 2.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright © 2001-2007 Red Hat, Inc.
562306a36Sopenharmony_ci * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org>
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Created by David Woodhouse <dwmw2@infradead.org>
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * For licensing information, see the file 'LICENCE' in this directory.
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/kernel.h>
1662306a36Sopenharmony_ci#include <linux/types.h>
1762306a36Sopenharmony_ci#include <linux/pagemap.h>
1862306a36Sopenharmony_ci#include <linux/crc32.h>
1962306a36Sopenharmony_ci#include <linux/jffs2.h>
2062306a36Sopenharmony_ci#include <linux/mtd/mtd.h>
2162306a36Sopenharmony_ci#include <linux/slab.h>
2262306a36Sopenharmony_ci#include "nodelist.h"
2362306a36Sopenharmony_ci#include "debug.h"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#ifdef JFFS2_DBG_SANITY_CHECKS
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_civoid
2862306a36Sopenharmony_ci__jffs2_dbg_acct_sanity_check_nolock(struct jffs2_sb_info *c,
2962306a36Sopenharmony_ci				     struct jffs2_eraseblock *jeb)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	if (unlikely(jeb && jeb->used_size + jeb->dirty_size +
3262306a36Sopenharmony_ci			jeb->free_size + jeb->wasted_size +
3362306a36Sopenharmony_ci			jeb->unchecked_size != c->sector_size)) {
3462306a36Sopenharmony_ci		JFFS2_ERROR("eeep, space accounting for block at 0x%08x is screwed.\n", jeb->offset);
3562306a36Sopenharmony_ci		JFFS2_ERROR("free %#08x + dirty %#08x + used %#08x + wasted %#08x + unchecked %#08x != total %#08x.\n",
3662306a36Sopenharmony_ci			jeb->free_size, jeb->dirty_size, jeb->used_size,
3762306a36Sopenharmony_ci			jeb->wasted_size, jeb->unchecked_size, c->sector_size);
3862306a36Sopenharmony_ci		BUG();
3962306a36Sopenharmony_ci	}
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	if (unlikely(c->used_size + c->dirty_size + c->free_size + c->erasing_size + c->bad_size
4262306a36Sopenharmony_ci				+ c->wasted_size + c->unchecked_size != c->flash_size)) {
4362306a36Sopenharmony_ci		JFFS2_ERROR("eeep, space accounting superblock info is screwed.\n");
4462306a36Sopenharmony_ci		JFFS2_ERROR("free %#08x + dirty %#08x + used %#08x + erasing %#08x + bad %#08x + wasted %#08x + unchecked %#08x != total %#08x.\n",
4562306a36Sopenharmony_ci			c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size,
4662306a36Sopenharmony_ci			c->wasted_size, c->unchecked_size, c->flash_size);
4762306a36Sopenharmony_ci		BUG();
4862306a36Sopenharmony_ci	}
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_civoid
5262306a36Sopenharmony_ci__jffs2_dbg_acct_sanity_check(struct jffs2_sb_info *c,
5362306a36Sopenharmony_ci			      struct jffs2_eraseblock *jeb)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	spin_lock(&c->erase_completion_lock);
5662306a36Sopenharmony_ci	jffs2_dbg_acct_sanity_check_nolock(c, jeb);
5762306a36Sopenharmony_ci	spin_unlock(&c->erase_completion_lock);
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci#endif /* JFFS2_DBG_SANITY_CHECKS */
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci#ifdef JFFS2_DBG_PARANOIA_CHECKS
6362306a36Sopenharmony_ci/*
6462306a36Sopenharmony_ci * Check the fragtree.
6562306a36Sopenharmony_ci */
6662306a36Sopenharmony_civoid
6762306a36Sopenharmony_ci__jffs2_dbg_fragtree_paranoia_check(struct jffs2_inode_info *f)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	mutex_lock(&f->sem);
7062306a36Sopenharmony_ci	__jffs2_dbg_fragtree_paranoia_check_nolock(f);
7162306a36Sopenharmony_ci	mutex_unlock(&f->sem);
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_civoid
7562306a36Sopenharmony_ci__jffs2_dbg_fragtree_paranoia_check_nolock(struct jffs2_inode_info *f)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	struct jffs2_node_frag *frag;
7862306a36Sopenharmony_ci	int bitched = 0;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) {
8162306a36Sopenharmony_ci		struct jffs2_full_dnode *fn = frag->node;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci		if (!fn || !fn->raw)
8462306a36Sopenharmony_ci			continue;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci		if (ref_flags(fn->raw) == REF_PRISTINE) {
8762306a36Sopenharmony_ci			if (fn->frags > 1) {
8862306a36Sopenharmony_ci				JFFS2_ERROR("REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2.\n",
8962306a36Sopenharmony_ci					ref_offset(fn->raw), fn->frags);
9062306a36Sopenharmony_ci				bitched = 1;
9162306a36Sopenharmony_ci			}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci			/* A hole node which isn't multi-page should be garbage-collected
9462306a36Sopenharmony_ci			   and merged anyway, so we just check for the frag size here,
9562306a36Sopenharmony_ci			   rather than mucking around with actually reading the node
9662306a36Sopenharmony_ci			   and checking the compression type, which is the real way
9762306a36Sopenharmony_ci			   to tell a hole node. */
9862306a36Sopenharmony_ci			if (frag->ofs & (PAGE_SIZE-1) && frag_prev(frag)
9962306a36Sopenharmony_ci					&& frag_prev(frag)->size < PAGE_SIZE && frag_prev(frag)->node) {
10062306a36Sopenharmony_ci				JFFS2_ERROR("REF_PRISTINE node at 0x%08x had a previous non-hole frag in the same page. Tell dwmw2.\n",
10162306a36Sopenharmony_ci					ref_offset(fn->raw));
10262306a36Sopenharmony_ci				bitched = 1;
10362306a36Sopenharmony_ci			}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci			if ((frag->ofs+frag->size) & (PAGE_SIZE-1) && frag_next(frag)
10662306a36Sopenharmony_ci					&& frag_next(frag)->size < PAGE_SIZE && frag_next(frag)->node) {
10762306a36Sopenharmony_ci				JFFS2_ERROR("REF_PRISTINE node at 0x%08x (%08x-%08x) had a following non-hole frag in the same page. Tell dwmw2.\n",
10862306a36Sopenharmony_ci				       ref_offset(fn->raw), frag->ofs, frag->ofs+frag->size);
10962306a36Sopenharmony_ci				bitched = 1;
11062306a36Sopenharmony_ci			}
11162306a36Sopenharmony_ci		}
11262306a36Sopenharmony_ci	}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	if (bitched) {
11562306a36Sopenharmony_ci		JFFS2_ERROR("fragtree is corrupted.\n");
11662306a36Sopenharmony_ci		__jffs2_dbg_dump_fragtree_nolock(f);
11762306a36Sopenharmony_ci		BUG();
11862306a36Sopenharmony_ci	}
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci/*
12262306a36Sopenharmony_ci * Check if the flash contains all 0xFF before we start writing.
12362306a36Sopenharmony_ci */
12462306a36Sopenharmony_civoid
12562306a36Sopenharmony_ci__jffs2_dbg_prewrite_paranoia_check(struct jffs2_sb_info *c,
12662306a36Sopenharmony_ci				    uint32_t ofs, int len)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	size_t retlen;
12962306a36Sopenharmony_ci	int ret, i;
13062306a36Sopenharmony_ci	unsigned char *buf;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	buf = kmalloc(len, GFP_KERNEL);
13362306a36Sopenharmony_ci	if (!buf)
13462306a36Sopenharmony_ci		return;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	ret = jffs2_flash_read(c, ofs, len, &retlen, buf);
13762306a36Sopenharmony_ci	if (ret || (retlen != len)) {
13862306a36Sopenharmony_ci		JFFS2_WARNING("read %d bytes failed or short. ret %d, retlen %zd.\n",
13962306a36Sopenharmony_ci				len, ret, retlen);
14062306a36Sopenharmony_ci		kfree(buf);
14162306a36Sopenharmony_ci		return;
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	ret = 0;
14562306a36Sopenharmony_ci	for (i = 0; i < len; i++)
14662306a36Sopenharmony_ci		if (buf[i] != 0xff)
14762306a36Sopenharmony_ci			ret = 1;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	if (ret) {
15062306a36Sopenharmony_ci		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",
15162306a36Sopenharmony_ci			ofs, ofs + i);
15262306a36Sopenharmony_ci		__jffs2_dbg_dump_buffer(buf, len, ofs);
15362306a36Sopenharmony_ci		kfree(buf);
15462306a36Sopenharmony_ci		BUG();
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	kfree(buf);
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_civoid __jffs2_dbg_superblock_counts(struct jffs2_sb_info *c)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	struct jffs2_eraseblock *jeb;
16362306a36Sopenharmony_ci	uint32_t free = 0, dirty = 0, used = 0, wasted = 0,
16462306a36Sopenharmony_ci		erasing = 0, bad = 0, unchecked = 0;
16562306a36Sopenharmony_ci	int nr_counted = 0;
16662306a36Sopenharmony_ci	int dump = 0;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	if (c->gcblock) {
16962306a36Sopenharmony_ci		nr_counted++;
17062306a36Sopenharmony_ci		free += c->gcblock->free_size;
17162306a36Sopenharmony_ci		dirty += c->gcblock->dirty_size;
17262306a36Sopenharmony_ci		used += c->gcblock->used_size;
17362306a36Sopenharmony_ci		wasted += c->gcblock->wasted_size;
17462306a36Sopenharmony_ci		unchecked += c->gcblock->unchecked_size;
17562306a36Sopenharmony_ci	}
17662306a36Sopenharmony_ci	if (c->nextblock) {
17762306a36Sopenharmony_ci		nr_counted++;
17862306a36Sopenharmony_ci		free += c->nextblock->free_size;
17962306a36Sopenharmony_ci		dirty += c->nextblock->dirty_size;
18062306a36Sopenharmony_ci		used += c->nextblock->used_size;
18162306a36Sopenharmony_ci		wasted += c->nextblock->wasted_size;
18262306a36Sopenharmony_ci		unchecked += c->nextblock->unchecked_size;
18362306a36Sopenharmony_ci	}
18462306a36Sopenharmony_ci	list_for_each_entry(jeb, &c->clean_list, list) {
18562306a36Sopenharmony_ci		nr_counted++;
18662306a36Sopenharmony_ci		free += jeb->free_size;
18762306a36Sopenharmony_ci		dirty += jeb->dirty_size;
18862306a36Sopenharmony_ci		used += jeb->used_size;
18962306a36Sopenharmony_ci		wasted += jeb->wasted_size;
19062306a36Sopenharmony_ci		unchecked += jeb->unchecked_size;
19162306a36Sopenharmony_ci	}
19262306a36Sopenharmony_ci	list_for_each_entry(jeb, &c->very_dirty_list, list) {
19362306a36Sopenharmony_ci		nr_counted++;
19462306a36Sopenharmony_ci		free += jeb->free_size;
19562306a36Sopenharmony_ci		dirty += jeb->dirty_size;
19662306a36Sopenharmony_ci		used += jeb->used_size;
19762306a36Sopenharmony_ci		wasted += jeb->wasted_size;
19862306a36Sopenharmony_ci		unchecked += jeb->unchecked_size;
19962306a36Sopenharmony_ci	}
20062306a36Sopenharmony_ci	list_for_each_entry(jeb, &c->dirty_list, list) {
20162306a36Sopenharmony_ci		nr_counted++;
20262306a36Sopenharmony_ci		free += jeb->free_size;
20362306a36Sopenharmony_ci		dirty += jeb->dirty_size;
20462306a36Sopenharmony_ci		used += jeb->used_size;
20562306a36Sopenharmony_ci		wasted += jeb->wasted_size;
20662306a36Sopenharmony_ci		unchecked += jeb->unchecked_size;
20762306a36Sopenharmony_ci	}
20862306a36Sopenharmony_ci	list_for_each_entry(jeb, &c->erasable_list, list) {
20962306a36Sopenharmony_ci		nr_counted++;
21062306a36Sopenharmony_ci		free += jeb->free_size;
21162306a36Sopenharmony_ci		dirty += jeb->dirty_size;
21262306a36Sopenharmony_ci		used += jeb->used_size;
21362306a36Sopenharmony_ci		wasted += jeb->wasted_size;
21462306a36Sopenharmony_ci		unchecked += jeb->unchecked_size;
21562306a36Sopenharmony_ci	}
21662306a36Sopenharmony_ci	list_for_each_entry(jeb, &c->erasable_pending_wbuf_list, list) {
21762306a36Sopenharmony_ci		nr_counted++;
21862306a36Sopenharmony_ci		free += jeb->free_size;
21962306a36Sopenharmony_ci		dirty += jeb->dirty_size;
22062306a36Sopenharmony_ci		used += jeb->used_size;
22162306a36Sopenharmony_ci		wasted += jeb->wasted_size;
22262306a36Sopenharmony_ci		unchecked += jeb->unchecked_size;
22362306a36Sopenharmony_ci	}
22462306a36Sopenharmony_ci	list_for_each_entry(jeb, &c->erase_pending_list, list) {
22562306a36Sopenharmony_ci		nr_counted++;
22662306a36Sopenharmony_ci		free += jeb->free_size;
22762306a36Sopenharmony_ci		dirty += jeb->dirty_size;
22862306a36Sopenharmony_ci		used += jeb->used_size;
22962306a36Sopenharmony_ci		wasted += jeb->wasted_size;
23062306a36Sopenharmony_ci		unchecked += jeb->unchecked_size;
23162306a36Sopenharmony_ci	}
23262306a36Sopenharmony_ci	list_for_each_entry(jeb, &c->free_list, list) {
23362306a36Sopenharmony_ci		nr_counted++;
23462306a36Sopenharmony_ci		free += jeb->free_size;
23562306a36Sopenharmony_ci		dirty += jeb->dirty_size;
23662306a36Sopenharmony_ci		used += jeb->used_size;
23762306a36Sopenharmony_ci		wasted += jeb->wasted_size;
23862306a36Sopenharmony_ci		unchecked += jeb->unchecked_size;
23962306a36Sopenharmony_ci	}
24062306a36Sopenharmony_ci	list_for_each_entry(jeb, &c->bad_used_list, list) {
24162306a36Sopenharmony_ci		nr_counted++;
24262306a36Sopenharmony_ci		free += jeb->free_size;
24362306a36Sopenharmony_ci		dirty += jeb->dirty_size;
24462306a36Sopenharmony_ci		used += jeb->used_size;
24562306a36Sopenharmony_ci		wasted += jeb->wasted_size;
24662306a36Sopenharmony_ci		unchecked += jeb->unchecked_size;
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	list_for_each_entry(jeb, &c->erasing_list, list) {
25062306a36Sopenharmony_ci		nr_counted++;
25162306a36Sopenharmony_ci		erasing += c->sector_size;
25262306a36Sopenharmony_ci	}
25362306a36Sopenharmony_ci	list_for_each_entry(jeb, &c->erase_checking_list, list) {
25462306a36Sopenharmony_ci		nr_counted++;
25562306a36Sopenharmony_ci		erasing += c->sector_size;
25662306a36Sopenharmony_ci	}
25762306a36Sopenharmony_ci	list_for_each_entry(jeb, &c->erase_complete_list, list) {
25862306a36Sopenharmony_ci		nr_counted++;
25962306a36Sopenharmony_ci		erasing += c->sector_size;
26062306a36Sopenharmony_ci	}
26162306a36Sopenharmony_ci	list_for_each_entry(jeb, &c->bad_list, list) {
26262306a36Sopenharmony_ci		nr_counted++;
26362306a36Sopenharmony_ci		bad += c->sector_size;
26462306a36Sopenharmony_ci	}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci#define check(sz)							\
26762306a36Sopenharmony_cido {									\
26862306a36Sopenharmony_ci	if (sz != c->sz##_size) {					\
26962306a36Sopenharmony_ci		pr_warn("%s_size mismatch counted 0x%x, c->%s_size 0x%x\n", \
27062306a36Sopenharmony_ci			#sz, sz, #sz, c->sz##_size);			\
27162306a36Sopenharmony_ci		dump = 1;						\
27262306a36Sopenharmony_ci	}								\
27362306a36Sopenharmony_ci} while (0)
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	check(free);
27662306a36Sopenharmony_ci	check(dirty);
27762306a36Sopenharmony_ci	check(used);
27862306a36Sopenharmony_ci	check(wasted);
27962306a36Sopenharmony_ci	check(unchecked);
28062306a36Sopenharmony_ci	check(bad);
28162306a36Sopenharmony_ci	check(erasing);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci#undef check
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	if (nr_counted != c->nr_blocks) {
28662306a36Sopenharmony_ci		pr_warn("%s counted only 0x%x blocks of 0x%x. Where are the others?\n",
28762306a36Sopenharmony_ci			__func__, nr_counted, c->nr_blocks);
28862306a36Sopenharmony_ci		dump = 1;
28962306a36Sopenharmony_ci	}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	if (dump) {
29262306a36Sopenharmony_ci		__jffs2_dbg_dump_block_lists_nolock(c);
29362306a36Sopenharmony_ci		BUG();
29462306a36Sopenharmony_ci	}
29562306a36Sopenharmony_ci}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci/*
29862306a36Sopenharmony_ci * Check the space accounting and node_ref list correctness for the JFFS2 erasable block 'jeb'.
29962306a36Sopenharmony_ci */
30062306a36Sopenharmony_civoid
30162306a36Sopenharmony_ci__jffs2_dbg_acct_paranoia_check(struct jffs2_sb_info *c,
30262306a36Sopenharmony_ci				struct jffs2_eraseblock *jeb)
30362306a36Sopenharmony_ci{
30462306a36Sopenharmony_ci	spin_lock(&c->erase_completion_lock);
30562306a36Sopenharmony_ci	__jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
30662306a36Sopenharmony_ci	spin_unlock(&c->erase_completion_lock);
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_civoid
31062306a36Sopenharmony_ci__jffs2_dbg_acct_paranoia_check_nolock(struct jffs2_sb_info *c,
31162306a36Sopenharmony_ci				       struct jffs2_eraseblock *jeb)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	uint32_t my_used_size = 0;
31462306a36Sopenharmony_ci	uint32_t my_unchecked_size = 0;
31562306a36Sopenharmony_ci	uint32_t my_dirty_size = 0;
31662306a36Sopenharmony_ci	struct jffs2_raw_node_ref *ref2 = jeb->first_node;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	while (ref2) {
31962306a36Sopenharmony_ci		uint32_t totlen = ref_totlen(c, jeb, ref2);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci		if (ref_offset(ref2) < jeb->offset ||
32262306a36Sopenharmony_ci				ref_offset(ref2) > jeb->offset + c->sector_size) {
32362306a36Sopenharmony_ci			JFFS2_ERROR("node_ref %#08x shouldn't be in block at %#08x.\n",
32462306a36Sopenharmony_ci				ref_offset(ref2), jeb->offset);
32562306a36Sopenharmony_ci			goto error;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci		}
32862306a36Sopenharmony_ci		if (ref_flags(ref2) == REF_UNCHECKED)
32962306a36Sopenharmony_ci			my_unchecked_size += totlen;
33062306a36Sopenharmony_ci		else if (!ref_obsolete(ref2))
33162306a36Sopenharmony_ci			my_used_size += totlen;
33262306a36Sopenharmony_ci		else
33362306a36Sopenharmony_ci			my_dirty_size += totlen;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci		if ((!ref_next(ref2)) != (ref2 == jeb->last_node)) {
33662306a36Sopenharmony_ci			JFFS2_ERROR("node_ref for node at %#08x (mem %p) has next at %#08x (mem %p), last_node is at %#08x (mem %p).\n",
33762306a36Sopenharmony_ci				    ref_offset(ref2), ref2, ref_offset(ref_next(ref2)), ref_next(ref2),
33862306a36Sopenharmony_ci				    ref_offset(jeb->last_node), jeb->last_node);
33962306a36Sopenharmony_ci			goto error;
34062306a36Sopenharmony_ci		}
34162306a36Sopenharmony_ci		ref2 = ref_next(ref2);
34262306a36Sopenharmony_ci	}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	if (my_used_size != jeb->used_size) {
34562306a36Sopenharmony_ci		JFFS2_ERROR("Calculated used size %#08x != stored used size %#08x.\n",
34662306a36Sopenharmony_ci			my_used_size, jeb->used_size);
34762306a36Sopenharmony_ci		goto error;
34862306a36Sopenharmony_ci	}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	if (my_unchecked_size != jeb->unchecked_size) {
35162306a36Sopenharmony_ci		JFFS2_ERROR("Calculated unchecked size %#08x != stored unchecked size %#08x.\n",
35262306a36Sopenharmony_ci			my_unchecked_size, jeb->unchecked_size);
35362306a36Sopenharmony_ci		goto error;
35462306a36Sopenharmony_ci	}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci#if 0
35762306a36Sopenharmony_ci	/* This should work when we implement ref->__totlen elemination */
35862306a36Sopenharmony_ci	if (my_dirty_size != jeb->dirty_size + jeb->wasted_size) {
35962306a36Sopenharmony_ci		JFFS2_ERROR("Calculated dirty+wasted size %#08x != stored dirty + wasted size %#08x\n",
36062306a36Sopenharmony_ci			my_dirty_size, jeb->dirty_size + jeb->wasted_size);
36162306a36Sopenharmony_ci		goto error;
36262306a36Sopenharmony_ci	}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	if (jeb->free_size == 0
36562306a36Sopenharmony_ci		&& my_used_size + my_unchecked_size + my_dirty_size != c->sector_size) {
36662306a36Sopenharmony_ci		JFFS2_ERROR("The sum of all nodes in block (%#x) != size of block (%#x)\n",
36762306a36Sopenharmony_ci			my_used_size + my_unchecked_size + my_dirty_size,
36862306a36Sopenharmony_ci			c->sector_size);
36962306a36Sopenharmony_ci		goto error;
37062306a36Sopenharmony_ci	}
37162306a36Sopenharmony_ci#endif
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	if (!(c->flags & (JFFS2_SB_FLAG_BUILDING|JFFS2_SB_FLAG_SCANNING)))
37462306a36Sopenharmony_ci		__jffs2_dbg_superblock_counts(c);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	return;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_cierror:
37962306a36Sopenharmony_ci	__jffs2_dbg_dump_node_refs_nolock(c, jeb);
38062306a36Sopenharmony_ci	__jffs2_dbg_dump_jeb_nolock(jeb);
38162306a36Sopenharmony_ci	__jffs2_dbg_dump_block_lists_nolock(c);
38262306a36Sopenharmony_ci	BUG();
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci#endif /* JFFS2_DBG_PARANOIA_CHECKS */
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci#if defined(JFFS2_DBG_DUMPS) || defined(JFFS2_DBG_PARANOIA_CHECKS)
38862306a36Sopenharmony_ci/*
38962306a36Sopenharmony_ci * Dump the node_refs of the 'jeb' JFFS2 eraseblock.
39062306a36Sopenharmony_ci */
39162306a36Sopenharmony_civoid
39262306a36Sopenharmony_ci__jffs2_dbg_dump_node_refs(struct jffs2_sb_info *c,
39362306a36Sopenharmony_ci			   struct jffs2_eraseblock *jeb)
39462306a36Sopenharmony_ci{
39562306a36Sopenharmony_ci	spin_lock(&c->erase_completion_lock);
39662306a36Sopenharmony_ci	__jffs2_dbg_dump_node_refs_nolock(c, jeb);
39762306a36Sopenharmony_ci	spin_unlock(&c->erase_completion_lock);
39862306a36Sopenharmony_ci}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_civoid
40162306a36Sopenharmony_ci__jffs2_dbg_dump_node_refs_nolock(struct jffs2_sb_info *c,
40262306a36Sopenharmony_ci				  struct jffs2_eraseblock *jeb)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	struct jffs2_raw_node_ref *ref;
40562306a36Sopenharmony_ci	int i = 0;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	printk(JFFS2_DBG_MSG_PREFIX " Dump node_refs of the eraseblock %#08x\n", jeb->offset);
40862306a36Sopenharmony_ci	if (!jeb->first_node) {
40962306a36Sopenharmony_ci		printk(JFFS2_DBG_MSG_PREFIX " no nodes in the eraseblock %#08x\n", jeb->offset);
41062306a36Sopenharmony_ci		return;
41162306a36Sopenharmony_ci	}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	printk(JFFS2_DBG);
41462306a36Sopenharmony_ci	for (ref = jeb->first_node; ; ref = ref_next(ref)) {
41562306a36Sopenharmony_ci		printk("%#08x", ref_offset(ref));
41662306a36Sopenharmony_ci#ifdef TEST_TOTLEN
41762306a36Sopenharmony_ci		printk("(%x)", ref->__totlen);
41862306a36Sopenharmony_ci#endif
41962306a36Sopenharmony_ci		if (ref_next(ref))
42062306a36Sopenharmony_ci			printk("->");
42162306a36Sopenharmony_ci		else
42262306a36Sopenharmony_ci			break;
42362306a36Sopenharmony_ci		if (++i == 4) {
42462306a36Sopenharmony_ci			i = 0;
42562306a36Sopenharmony_ci			printk("\n" JFFS2_DBG);
42662306a36Sopenharmony_ci		}
42762306a36Sopenharmony_ci	}
42862306a36Sopenharmony_ci	printk("\n");
42962306a36Sopenharmony_ci}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci/*
43262306a36Sopenharmony_ci * Dump an eraseblock's space accounting.
43362306a36Sopenharmony_ci */
43462306a36Sopenharmony_civoid
43562306a36Sopenharmony_ci__jffs2_dbg_dump_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
43662306a36Sopenharmony_ci{
43762306a36Sopenharmony_ci	spin_lock(&c->erase_completion_lock);
43862306a36Sopenharmony_ci	__jffs2_dbg_dump_jeb_nolock(jeb);
43962306a36Sopenharmony_ci	spin_unlock(&c->erase_completion_lock);
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_civoid
44362306a36Sopenharmony_ci__jffs2_dbg_dump_jeb_nolock(struct jffs2_eraseblock *jeb)
44462306a36Sopenharmony_ci{
44562306a36Sopenharmony_ci	if (!jeb)
44662306a36Sopenharmony_ci		return;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	printk(JFFS2_DBG_MSG_PREFIX " dump space accounting for the eraseblock at %#08x:\n",
44962306a36Sopenharmony_ci			jeb->offset);
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	printk(JFFS2_DBG "used_size: %#08x\n",		jeb->used_size);
45262306a36Sopenharmony_ci	printk(JFFS2_DBG "dirty_size: %#08x\n",		jeb->dirty_size);
45362306a36Sopenharmony_ci	printk(JFFS2_DBG "wasted_size: %#08x\n",	jeb->wasted_size);
45462306a36Sopenharmony_ci	printk(JFFS2_DBG "unchecked_size: %#08x\n",	jeb->unchecked_size);
45562306a36Sopenharmony_ci	printk(JFFS2_DBG "free_size: %#08x\n",		jeb->free_size);
45662306a36Sopenharmony_ci}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_civoid
45962306a36Sopenharmony_ci__jffs2_dbg_dump_block_lists(struct jffs2_sb_info *c)
46062306a36Sopenharmony_ci{
46162306a36Sopenharmony_ci	spin_lock(&c->erase_completion_lock);
46262306a36Sopenharmony_ci	__jffs2_dbg_dump_block_lists_nolock(c);
46362306a36Sopenharmony_ci	spin_unlock(&c->erase_completion_lock);
46462306a36Sopenharmony_ci}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_civoid
46762306a36Sopenharmony_ci__jffs2_dbg_dump_block_lists_nolock(struct jffs2_sb_info *c)
46862306a36Sopenharmony_ci{
46962306a36Sopenharmony_ci	printk(JFFS2_DBG_MSG_PREFIX " dump JFFS2 blocks lists:\n");
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	printk(JFFS2_DBG "flash_size: %#08x\n",		c->flash_size);
47262306a36Sopenharmony_ci	printk(JFFS2_DBG "used_size: %#08x\n",		c->used_size);
47362306a36Sopenharmony_ci	printk(JFFS2_DBG "dirty_size: %#08x\n",		c->dirty_size);
47462306a36Sopenharmony_ci	printk(JFFS2_DBG "wasted_size: %#08x\n",	c->wasted_size);
47562306a36Sopenharmony_ci	printk(JFFS2_DBG "unchecked_size: %#08x\n",	c->unchecked_size);
47662306a36Sopenharmony_ci	printk(JFFS2_DBG "free_size: %#08x\n",		c->free_size);
47762306a36Sopenharmony_ci	printk(JFFS2_DBG "erasing_size: %#08x\n",	c->erasing_size);
47862306a36Sopenharmony_ci	printk(JFFS2_DBG "bad_size: %#08x\n",		c->bad_size);
47962306a36Sopenharmony_ci	printk(JFFS2_DBG "sector_size: %#08x\n",	c->sector_size);
48062306a36Sopenharmony_ci	printk(JFFS2_DBG "jffs2_reserved_blocks size: %#08x\n",
48162306a36Sopenharmony_ci				c->sector_size * c->resv_blocks_write);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	if (c->nextblock)
48462306a36Sopenharmony_ci		printk(JFFS2_DBG "nextblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
48562306a36Sopenharmony_ci			c->nextblock->offset, c->nextblock->used_size,
48662306a36Sopenharmony_ci			c->nextblock->dirty_size, c->nextblock->wasted_size,
48762306a36Sopenharmony_ci			c->nextblock->unchecked_size, c->nextblock->free_size);
48862306a36Sopenharmony_ci	else
48962306a36Sopenharmony_ci		printk(JFFS2_DBG "nextblock: NULL\n");
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	if (c->gcblock)
49262306a36Sopenharmony_ci		printk(JFFS2_DBG "gcblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
49362306a36Sopenharmony_ci			c->gcblock->offset, c->gcblock->used_size, c->gcblock->dirty_size,
49462306a36Sopenharmony_ci			c->gcblock->wasted_size, c->gcblock->unchecked_size, c->gcblock->free_size);
49562306a36Sopenharmony_ci	else
49662306a36Sopenharmony_ci		printk(JFFS2_DBG "gcblock: NULL\n");
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	if (list_empty(&c->clean_list)) {
49962306a36Sopenharmony_ci		printk(JFFS2_DBG "clean_list: empty\n");
50062306a36Sopenharmony_ci	} else {
50162306a36Sopenharmony_ci		struct list_head *this;
50262306a36Sopenharmony_ci		int numblocks = 0;
50362306a36Sopenharmony_ci		uint32_t dirty = 0;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci		list_for_each(this, &c->clean_list) {
50662306a36Sopenharmony_ci			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
50762306a36Sopenharmony_ci			numblocks ++;
50862306a36Sopenharmony_ci			dirty += jeb->wasted_size;
50962306a36Sopenharmony_ci			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
51062306a36Sopenharmony_ci				printk(JFFS2_DBG "clean_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
51162306a36Sopenharmony_ci					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
51262306a36Sopenharmony_ci					jeb->unchecked_size, jeb->free_size);
51362306a36Sopenharmony_ci			}
51462306a36Sopenharmony_ci		}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci		printk (JFFS2_DBG "Contains %d blocks with total wasted size %u, average wasted size: %u\n",
51762306a36Sopenharmony_ci			numblocks, dirty, dirty / numblocks);
51862306a36Sopenharmony_ci	}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	if (list_empty(&c->very_dirty_list)) {
52162306a36Sopenharmony_ci		printk(JFFS2_DBG "very_dirty_list: empty\n");
52262306a36Sopenharmony_ci	} else {
52362306a36Sopenharmony_ci		struct list_head *this;
52462306a36Sopenharmony_ci		int numblocks = 0;
52562306a36Sopenharmony_ci		uint32_t dirty = 0;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci		list_for_each(this, &c->very_dirty_list) {
52862306a36Sopenharmony_ci			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci			numblocks ++;
53162306a36Sopenharmony_ci			dirty += jeb->dirty_size;
53262306a36Sopenharmony_ci			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
53362306a36Sopenharmony_ci				printk(JFFS2_DBG "very_dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
53462306a36Sopenharmony_ci					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
53562306a36Sopenharmony_ci					jeb->unchecked_size, jeb->free_size);
53662306a36Sopenharmony_ci			}
53762306a36Sopenharmony_ci		}
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci		printk (JFFS2_DBG "Contains %d blocks with total dirty size %u, average dirty size: %u\n",
54062306a36Sopenharmony_ci			numblocks, dirty, dirty / numblocks);
54162306a36Sopenharmony_ci	}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	if (list_empty(&c->dirty_list)) {
54462306a36Sopenharmony_ci		printk(JFFS2_DBG "dirty_list: empty\n");
54562306a36Sopenharmony_ci	} else {
54662306a36Sopenharmony_ci		struct list_head *this;
54762306a36Sopenharmony_ci		int numblocks = 0;
54862306a36Sopenharmony_ci		uint32_t dirty = 0;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci		list_for_each(this, &c->dirty_list) {
55162306a36Sopenharmony_ci			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci			numblocks ++;
55462306a36Sopenharmony_ci			dirty += jeb->dirty_size;
55562306a36Sopenharmony_ci			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
55662306a36Sopenharmony_ci				printk(JFFS2_DBG "dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
55762306a36Sopenharmony_ci					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
55862306a36Sopenharmony_ci					jeb->unchecked_size, jeb->free_size);
55962306a36Sopenharmony_ci			}
56062306a36Sopenharmony_ci		}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci		printk (JFFS2_DBG "contains %d blocks with total dirty size %u, average dirty size: %u\n",
56362306a36Sopenharmony_ci			numblocks, dirty, dirty / numblocks);
56462306a36Sopenharmony_ci	}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	if (list_empty(&c->erasable_list)) {
56762306a36Sopenharmony_ci		printk(JFFS2_DBG "erasable_list: empty\n");
56862306a36Sopenharmony_ci	} else {
56962306a36Sopenharmony_ci		struct list_head *this;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci		list_for_each(this, &c->erasable_list) {
57262306a36Sopenharmony_ci			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
57562306a36Sopenharmony_ci				printk(JFFS2_DBG "erasable_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
57662306a36Sopenharmony_ci					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
57762306a36Sopenharmony_ci					jeb->unchecked_size, jeb->free_size);
57862306a36Sopenharmony_ci			}
57962306a36Sopenharmony_ci		}
58062306a36Sopenharmony_ci	}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	if (list_empty(&c->erasing_list)) {
58362306a36Sopenharmony_ci		printk(JFFS2_DBG "erasing_list: empty\n");
58462306a36Sopenharmony_ci	} else {
58562306a36Sopenharmony_ci		struct list_head *this;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci		list_for_each(this, &c->erasing_list) {
58862306a36Sopenharmony_ci			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
59162306a36Sopenharmony_ci				printk(JFFS2_DBG "erasing_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
59262306a36Sopenharmony_ci					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
59362306a36Sopenharmony_ci					jeb->unchecked_size, jeb->free_size);
59462306a36Sopenharmony_ci			}
59562306a36Sopenharmony_ci		}
59662306a36Sopenharmony_ci	}
59762306a36Sopenharmony_ci	if (list_empty(&c->erase_checking_list)) {
59862306a36Sopenharmony_ci		printk(JFFS2_DBG "erase_checking_list: empty\n");
59962306a36Sopenharmony_ci	} else {
60062306a36Sopenharmony_ci		struct list_head *this;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci		list_for_each(this, &c->erase_checking_list) {
60362306a36Sopenharmony_ci			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
60662306a36Sopenharmony_ci				printk(JFFS2_DBG "erase_checking_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
60762306a36Sopenharmony_ci					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
60862306a36Sopenharmony_ci					jeb->unchecked_size, jeb->free_size);
60962306a36Sopenharmony_ci			}
61062306a36Sopenharmony_ci		}
61162306a36Sopenharmony_ci	}
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	if (list_empty(&c->erase_pending_list)) {
61462306a36Sopenharmony_ci		printk(JFFS2_DBG "erase_pending_list: empty\n");
61562306a36Sopenharmony_ci	} else {
61662306a36Sopenharmony_ci		struct list_head *this;
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci		list_for_each(this, &c->erase_pending_list) {
61962306a36Sopenharmony_ci			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
62262306a36Sopenharmony_ci				printk(JFFS2_DBG "erase_pending_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
62362306a36Sopenharmony_ci					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
62462306a36Sopenharmony_ci					jeb->unchecked_size, jeb->free_size);
62562306a36Sopenharmony_ci			}
62662306a36Sopenharmony_ci		}
62762306a36Sopenharmony_ci	}
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	if (list_empty(&c->erasable_pending_wbuf_list)) {
63062306a36Sopenharmony_ci		printk(JFFS2_DBG "erasable_pending_wbuf_list: empty\n");
63162306a36Sopenharmony_ci	} else {
63262306a36Sopenharmony_ci		struct list_head *this;
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci		list_for_each(this, &c->erasable_pending_wbuf_list) {
63562306a36Sopenharmony_ci			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
63862306a36Sopenharmony_ci				printk(JFFS2_DBG "erasable_pending_wbuf_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
63962306a36Sopenharmony_ci					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
64062306a36Sopenharmony_ci					jeb->unchecked_size, jeb->free_size);
64162306a36Sopenharmony_ci			}
64262306a36Sopenharmony_ci		}
64362306a36Sopenharmony_ci	}
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	if (list_empty(&c->free_list)) {
64662306a36Sopenharmony_ci		printk(JFFS2_DBG "free_list: empty\n");
64762306a36Sopenharmony_ci	} else {
64862306a36Sopenharmony_ci		struct list_head *this;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci		list_for_each(this, &c->free_list) {
65162306a36Sopenharmony_ci			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
65462306a36Sopenharmony_ci				printk(JFFS2_DBG "free_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
65562306a36Sopenharmony_ci					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
65662306a36Sopenharmony_ci					jeb->unchecked_size, jeb->free_size);
65762306a36Sopenharmony_ci			}
65862306a36Sopenharmony_ci		}
65962306a36Sopenharmony_ci	}
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	if (list_empty(&c->bad_list)) {
66262306a36Sopenharmony_ci		printk(JFFS2_DBG "bad_list: empty\n");
66362306a36Sopenharmony_ci	} else {
66462306a36Sopenharmony_ci		struct list_head *this;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci		list_for_each(this, &c->bad_list) {
66762306a36Sopenharmony_ci			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
67062306a36Sopenharmony_ci				printk(JFFS2_DBG "bad_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
67162306a36Sopenharmony_ci					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
67262306a36Sopenharmony_ci					jeb->unchecked_size, jeb->free_size);
67362306a36Sopenharmony_ci			}
67462306a36Sopenharmony_ci		}
67562306a36Sopenharmony_ci	}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	if (list_empty(&c->bad_used_list)) {
67862306a36Sopenharmony_ci		printk(JFFS2_DBG "bad_used_list: empty\n");
67962306a36Sopenharmony_ci	} else {
68062306a36Sopenharmony_ci		struct list_head *this;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci		list_for_each(this, &c->bad_used_list) {
68362306a36Sopenharmony_ci			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
68662306a36Sopenharmony_ci				printk(JFFS2_DBG "bad_used_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
68762306a36Sopenharmony_ci					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
68862306a36Sopenharmony_ci					jeb->unchecked_size, jeb->free_size);
68962306a36Sopenharmony_ci			}
69062306a36Sopenharmony_ci		}
69162306a36Sopenharmony_ci	}
69262306a36Sopenharmony_ci}
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_civoid
69562306a36Sopenharmony_ci__jffs2_dbg_dump_fragtree(struct jffs2_inode_info *f)
69662306a36Sopenharmony_ci{
69762306a36Sopenharmony_ci	mutex_lock(&f->sem);
69862306a36Sopenharmony_ci	jffs2_dbg_dump_fragtree_nolock(f);
69962306a36Sopenharmony_ci	mutex_unlock(&f->sem);
70062306a36Sopenharmony_ci}
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_civoid
70362306a36Sopenharmony_ci__jffs2_dbg_dump_fragtree_nolock(struct jffs2_inode_info *f)
70462306a36Sopenharmony_ci{
70562306a36Sopenharmony_ci	struct jffs2_node_frag *this = frag_first(&f->fragtree);
70662306a36Sopenharmony_ci	uint32_t lastofs = 0;
70762306a36Sopenharmony_ci	int buggy = 0;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	printk(JFFS2_DBG_MSG_PREFIX " dump fragtree of ino #%u\n", f->inocache->ino);
71062306a36Sopenharmony_ci	while(this) {
71162306a36Sopenharmony_ci		if (this->node)
71262306a36Sopenharmony_ci			printk(JFFS2_DBG "frag %#04x-%#04x: %#08x(%d) on flash (*%p), left (%p), right (%p), parent (%p)\n",
71362306a36Sopenharmony_ci				this->ofs, this->ofs+this->size, ref_offset(this->node->raw),
71462306a36Sopenharmony_ci				ref_flags(this->node->raw), this, frag_left(this), frag_right(this),
71562306a36Sopenharmony_ci				frag_parent(this));
71662306a36Sopenharmony_ci		else
71762306a36Sopenharmony_ci			printk(JFFS2_DBG "frag %#04x-%#04x: hole (*%p). left (%p), right (%p), parent (%p)\n",
71862306a36Sopenharmony_ci				this->ofs, this->ofs+this->size, this, frag_left(this),
71962306a36Sopenharmony_ci				frag_right(this), frag_parent(this));
72062306a36Sopenharmony_ci		if (this->ofs != lastofs)
72162306a36Sopenharmony_ci			buggy = 1;
72262306a36Sopenharmony_ci		lastofs = this->ofs + this->size;
72362306a36Sopenharmony_ci		this = frag_next(this);
72462306a36Sopenharmony_ci	}
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	if (f->metadata)
72762306a36Sopenharmony_ci		printk(JFFS2_DBG "metadata at 0x%08x\n", ref_offset(f->metadata->raw));
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	if (buggy) {
73062306a36Sopenharmony_ci		JFFS2_ERROR("frag tree got a hole in it.\n");
73162306a36Sopenharmony_ci		BUG();
73262306a36Sopenharmony_ci	}
73362306a36Sopenharmony_ci}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci#define JFFS2_BUFDUMP_BYTES_PER_LINE	32
73662306a36Sopenharmony_civoid
73762306a36Sopenharmony_ci__jffs2_dbg_dump_buffer(unsigned char *buf, int len, uint32_t offs)
73862306a36Sopenharmony_ci{
73962306a36Sopenharmony_ci	int skip;
74062306a36Sopenharmony_ci	int i;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	printk(JFFS2_DBG_MSG_PREFIX " dump from offset %#08x to offset %#08x (%x bytes).\n",
74362306a36Sopenharmony_ci		offs, offs + len, len);
74462306a36Sopenharmony_ci	i = skip = offs % JFFS2_BUFDUMP_BYTES_PER_LINE;
74562306a36Sopenharmony_ci	offs = offs & ~(JFFS2_BUFDUMP_BYTES_PER_LINE - 1);
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	if (skip != 0)
74862306a36Sopenharmony_ci		printk(JFFS2_DBG "%#08x: ", offs);
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	while (skip--)
75162306a36Sopenharmony_ci		printk("   ");
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	while (i < len) {
75462306a36Sopenharmony_ci		if ((i % JFFS2_BUFDUMP_BYTES_PER_LINE) == 0 && i != len -1) {
75562306a36Sopenharmony_ci			if (i != 0)
75662306a36Sopenharmony_ci				printk("\n");
75762306a36Sopenharmony_ci			offs += JFFS2_BUFDUMP_BYTES_PER_LINE;
75862306a36Sopenharmony_ci			printk(JFFS2_DBG "%0#8x: ", offs);
75962306a36Sopenharmony_ci		}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci		printk("%02x ", buf[i]);
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci		i += 1;
76462306a36Sopenharmony_ci	}
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	printk("\n");
76762306a36Sopenharmony_ci}
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci/*
77062306a36Sopenharmony_ci * Dump a JFFS2 node.
77162306a36Sopenharmony_ci */
77262306a36Sopenharmony_civoid
77362306a36Sopenharmony_ci__jffs2_dbg_dump_node(struct jffs2_sb_info *c, uint32_t ofs)
77462306a36Sopenharmony_ci{
77562306a36Sopenharmony_ci	union jffs2_node_union node;
77662306a36Sopenharmony_ci	int len = sizeof(union jffs2_node_union);
77762306a36Sopenharmony_ci	size_t retlen;
77862306a36Sopenharmony_ci	uint32_t crc;
77962306a36Sopenharmony_ci	int ret;
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	printk(JFFS2_DBG_MSG_PREFIX " dump node at offset %#08x.\n", ofs);
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	ret = jffs2_flash_read(c, ofs, len, &retlen, (unsigned char *)&node);
78462306a36Sopenharmony_ci	if (ret || (retlen != len)) {
78562306a36Sopenharmony_ci		JFFS2_ERROR("read %d bytes failed or short. ret %d, retlen %zd.\n",
78662306a36Sopenharmony_ci			len, ret, retlen);
78762306a36Sopenharmony_ci		return;
78862306a36Sopenharmony_ci	}
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	printk(JFFS2_DBG "magic:\t%#04x\n", je16_to_cpu(node.u.magic));
79162306a36Sopenharmony_ci	printk(JFFS2_DBG "nodetype:\t%#04x\n", je16_to_cpu(node.u.nodetype));
79262306a36Sopenharmony_ci	printk(JFFS2_DBG "totlen:\t%#08x\n", je32_to_cpu(node.u.totlen));
79362306a36Sopenharmony_ci	printk(JFFS2_DBG "hdr_crc:\t%#08x\n", je32_to_cpu(node.u.hdr_crc));
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	crc = crc32(0, &node.u, sizeof(node.u) - 4);
79662306a36Sopenharmony_ci	if (crc != je32_to_cpu(node.u.hdr_crc)) {
79762306a36Sopenharmony_ci		JFFS2_ERROR("wrong common header CRC.\n");
79862306a36Sopenharmony_ci		return;
79962306a36Sopenharmony_ci	}
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	if (je16_to_cpu(node.u.magic) != JFFS2_MAGIC_BITMASK &&
80262306a36Sopenharmony_ci		je16_to_cpu(node.u.magic) != JFFS2_OLD_MAGIC_BITMASK)
80362306a36Sopenharmony_ci	{
80462306a36Sopenharmony_ci		JFFS2_ERROR("wrong node magic: %#04x instead of %#04x.\n",
80562306a36Sopenharmony_ci			je16_to_cpu(node.u.magic), JFFS2_MAGIC_BITMASK);
80662306a36Sopenharmony_ci		return;
80762306a36Sopenharmony_ci	}
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	switch(je16_to_cpu(node.u.nodetype)) {
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	case JFFS2_NODETYPE_INODE:
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci		printk(JFFS2_DBG "the node is inode node\n");
81462306a36Sopenharmony_ci		printk(JFFS2_DBG "ino:\t%#08x\n", je32_to_cpu(node.i.ino));
81562306a36Sopenharmony_ci		printk(JFFS2_DBG "version:\t%#08x\n", je32_to_cpu(node.i.version));
81662306a36Sopenharmony_ci		printk(JFFS2_DBG "mode:\t%#08x\n", node.i.mode.m);
81762306a36Sopenharmony_ci		printk(JFFS2_DBG "uid:\t%#04x\n", je16_to_cpu(node.i.uid));
81862306a36Sopenharmony_ci		printk(JFFS2_DBG "gid:\t%#04x\n", je16_to_cpu(node.i.gid));
81962306a36Sopenharmony_ci		printk(JFFS2_DBG "isize:\t%#08x\n", je32_to_cpu(node.i.isize));
82062306a36Sopenharmony_ci		printk(JFFS2_DBG "atime:\t%#08x\n", je32_to_cpu(node.i.atime));
82162306a36Sopenharmony_ci		printk(JFFS2_DBG "mtime:\t%#08x\n", je32_to_cpu(node.i.mtime));
82262306a36Sopenharmony_ci		printk(JFFS2_DBG "ctime:\t%#08x\n", je32_to_cpu(node.i.ctime));
82362306a36Sopenharmony_ci		printk(JFFS2_DBG "offset:\t%#08x\n", je32_to_cpu(node.i.offset));
82462306a36Sopenharmony_ci		printk(JFFS2_DBG "csize:\t%#08x\n", je32_to_cpu(node.i.csize));
82562306a36Sopenharmony_ci		printk(JFFS2_DBG "dsize:\t%#08x\n", je32_to_cpu(node.i.dsize));
82662306a36Sopenharmony_ci		printk(JFFS2_DBG "compr:\t%#02x\n", node.i.compr);
82762306a36Sopenharmony_ci		printk(JFFS2_DBG "usercompr:\t%#02x\n", node.i.usercompr);
82862306a36Sopenharmony_ci		printk(JFFS2_DBG "flags:\t%#04x\n", je16_to_cpu(node.i.flags));
82962306a36Sopenharmony_ci		printk(JFFS2_DBG "data_crc:\t%#08x\n", je32_to_cpu(node.i.data_crc));
83062306a36Sopenharmony_ci		printk(JFFS2_DBG "node_crc:\t%#08x\n", je32_to_cpu(node.i.node_crc));
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci		crc = crc32(0, &node.i, sizeof(node.i) - 8);
83362306a36Sopenharmony_ci		if (crc != je32_to_cpu(node.i.node_crc)) {
83462306a36Sopenharmony_ci			JFFS2_ERROR("wrong node header CRC.\n");
83562306a36Sopenharmony_ci			return;
83662306a36Sopenharmony_ci		}
83762306a36Sopenharmony_ci		break;
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	case JFFS2_NODETYPE_DIRENT:
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci		printk(JFFS2_DBG "the node is dirent node\n");
84262306a36Sopenharmony_ci		printk(JFFS2_DBG "pino:\t%#08x\n", je32_to_cpu(node.d.pino));
84362306a36Sopenharmony_ci		printk(JFFS2_DBG "version:\t%#08x\n", je32_to_cpu(node.d.version));
84462306a36Sopenharmony_ci		printk(JFFS2_DBG "ino:\t%#08x\n", je32_to_cpu(node.d.ino));
84562306a36Sopenharmony_ci		printk(JFFS2_DBG "mctime:\t%#08x\n", je32_to_cpu(node.d.mctime));
84662306a36Sopenharmony_ci		printk(JFFS2_DBG "nsize:\t%#02x\n", node.d.nsize);
84762306a36Sopenharmony_ci		printk(JFFS2_DBG "type:\t%#02x\n", node.d.type);
84862306a36Sopenharmony_ci		printk(JFFS2_DBG "node_crc:\t%#08x\n", je32_to_cpu(node.d.node_crc));
84962306a36Sopenharmony_ci		printk(JFFS2_DBG "name_crc:\t%#08x\n", je32_to_cpu(node.d.name_crc));
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci		node.d.name[node.d.nsize] = '\0';
85262306a36Sopenharmony_ci		printk(JFFS2_DBG "name:\t\"%s\"\n", node.d.name);
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci		crc = crc32(0, &node.d, sizeof(node.d) - 8);
85562306a36Sopenharmony_ci		if (crc != je32_to_cpu(node.d.node_crc)) {
85662306a36Sopenharmony_ci			JFFS2_ERROR("wrong node header CRC.\n");
85762306a36Sopenharmony_ci			return;
85862306a36Sopenharmony_ci		}
85962306a36Sopenharmony_ci		break;
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	default:
86262306a36Sopenharmony_ci		printk(JFFS2_DBG "node type is unknown\n");
86362306a36Sopenharmony_ci		break;
86462306a36Sopenharmony_ci	}
86562306a36Sopenharmony_ci}
86662306a36Sopenharmony_ci#endif /* JFFS2_DBG_DUMPS || JFFS2_DBG_PARANOIA_CHECKS */
867