blob: 1fe17de713e86dabb250a5a471d8d57d0eec2f2a [file] [log] [blame]
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +01001/*
2 * JFFS2 -- Journalling Flash File System, Version 2.
3 *
4 * Copyright (C) 2001-2003 Red Hat, Inc.
5 *
6 * Created by David Woodhouse <dwmw2@infradead.org>
7 *
8 * For licensing information, see the file 'LICENCE' in this directory.
9 *
Thomas Gleixner182ec4e2005-11-07 11:16:07 +000010 * $Id: debug.c,v 1.12 2005/11/07 11:14:39 gleixner Exp $
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +010011 *
12 */
13#include <linux/kernel.h>
Andrew Lunn737b7662005-07-30 16:29:30 +010014#include <linux/types.h>
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +010015#include <linux/pagemap.h>
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +010016#include <linux/crc32.h>
17#include <linux/jffs2.h>
Artem B. Bityutskiy733802d2005-09-22 12:25:00 +010018#include <linux/mtd/mtd.h>
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +010019#include "nodelist.h"
20#include "debug.h"
21
Artem B. Bityutskiy45ca1b52005-08-05 12:43:47 +010022#ifdef JFFS2_DBG_SANITY_CHECKS
23
24void
25__jffs2_dbg_acct_sanity_check_nolock(struct jffs2_sb_info *c,
26 struct jffs2_eraseblock *jeb)
27{
28 if (unlikely(jeb && jeb->used_size + jeb->dirty_size +
29 jeb->free_size + jeb->wasted_size +
30 jeb->unchecked_size != c->sector_size)) {
31 JFFS2_ERROR("eeep, space accounting for block at 0x%08x is screwed.\n", jeb->offset);
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +010032 JFFS2_ERROR("free %#08x + dirty %#08x + used %#08x + wasted %#08x + unchecked %#08x != total %#08x.\n",
33 jeb->free_size, jeb->dirty_size, jeb->used_size,
Artem B. Bityutskiy45ca1b52005-08-05 12:43:47 +010034 jeb->wasted_size, jeb->unchecked_size, c->sector_size);
35 BUG();
36 }
37
38 if (unlikely(c->used_size + c->dirty_size + c->free_size + c->erasing_size + c->bad_size
39 + c->wasted_size + c->unchecked_size != c->flash_size)) {
40 JFFS2_ERROR("eeep, space accounting superblock info is screwed.\n");
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +010041 JFFS2_ERROR("free %#08x + dirty %#08x + used %#08x + erasing %#08x + bad %#08x + wasted %#08x + unchecked %#08x != total %#08x.\n",
Artem B. Bityutskiy45ca1b52005-08-05 12:43:47 +010042 c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size,
43 c->wasted_size, c->unchecked_size, c->flash_size);
44 BUG();
45 }
46}
47
48void
49__jffs2_dbg_acct_sanity_check(struct jffs2_sb_info *c,
50 struct jffs2_eraseblock *jeb)
51{
52 spin_lock(&c->erase_completion_lock);
53 jffs2_dbg_acct_sanity_check_nolock(c, jeb);
54 spin_unlock(&c->erase_completion_lock);
55}
56
57#endif /* JFFS2_DBG_SANITY_CHECKS */
58
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +010059#ifdef JFFS2_DBG_PARANOIA_CHECKS
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +010060/*
61 * Check the fragtree.
62 */
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +010063void
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +010064__jffs2_dbg_fragtree_paranoia_check(struct jffs2_inode_info *f)
65{
66 down(&f->sem);
67 __jffs2_dbg_fragtree_paranoia_check_nolock(f);
68 up(&f->sem);
69}
Thomas Gleixner182ec4e2005-11-07 11:16:07 +000070
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +010071void
72__jffs2_dbg_fragtree_paranoia_check_nolock(struct jffs2_inode_info *f)
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +010073{
74 struct jffs2_node_frag *frag;
75 int bitched = 0;
76
77 for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) {
78 struct jffs2_full_dnode *fn = frag->node;
79
80 if (!fn || !fn->raw)
81 continue;
82
83 if (ref_flags(fn->raw) == REF_PRISTINE) {
84 if (fn->frags > 1) {
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +010085 JFFS2_ERROR("REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2.\n",
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +010086 ref_offset(fn->raw), fn->frags);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +010087 bitched = 1;
88 }
89
90 /* A hole node which isn't multi-page should be garbage-collected
91 and merged anyway, so we just check for the frag size here,
92 rather than mucking around with actually reading the node
93 and checking the compression type, which is the real way
94 to tell a hole node. */
95 if (frag->ofs & (PAGE_CACHE_SIZE-1) && frag_prev(frag)
96 && frag_prev(frag)->size < PAGE_CACHE_SIZE && frag_prev(frag)->node) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +010097 JFFS2_ERROR("REF_PRISTINE node at 0x%08x had a previous non-hole frag in the same page. Tell dwmw2.\n",
98 ref_offset(fn->raw));
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +010099 bitched = 1;
100 }
101
102 if ((frag->ofs+frag->size) & (PAGE_CACHE_SIZE-1) && frag_next(frag)
103 && frag_next(frag)->size < PAGE_CACHE_SIZE && frag_next(frag)->node) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100104 JFFS2_ERROR("REF_PRISTINE node at 0x%08x (%08x-%08x) had a following non-hole frag in the same page. Tell dwmw2.\n",
105 ref_offset(fn->raw), frag->ofs, frag->ofs+frag->size);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100106 bitched = 1;
107 }
108 }
109 }
110
111 if (bitched) {
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100112 JFFS2_ERROR("fragtree is corrupted.\n");
113 __jffs2_dbg_dump_fragtree_nolock(f);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100114 BUG();
115 }
116}
117
118/*
119 * Check if the flash contains all 0xFF before we start writing.
120 */
121void
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100122__jffs2_dbg_prewrite_paranoia_check(struct jffs2_sb_info *c,
123 uint32_t ofs, int len)
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100124{
125 size_t retlen;
126 int ret, i;
127 unsigned char *buf;
128
129 buf = kmalloc(len, GFP_KERNEL);
130 if (!buf)
131 return;
132
133 ret = jffs2_flash_read(c, ofs, len, &retlen, buf);
134 if (ret || (retlen != len)) {
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100135 JFFS2_WARNING("read %d bytes failed or short. ret %d, retlen %zd.\n",
136 len, ret, retlen);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100137 kfree(buf);
138 return;
139 }
140
141 ret = 0;
142 for (i = 0; i < len; i++)
143 if (buf[i] != 0xff)
144 ret = 1;
145
146 if (ret) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100147 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",
148 ofs, ofs + i);
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100149 __jffs2_dbg_dump_buffer(buf, len, ofs);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100150 kfree(buf);
151 BUG();
152 }
153
154 kfree(buf);
155}
156
157/*
158 * Check the space accounting and node_ref list correctness for the JFFS2 erasable block 'jeb'.
159 */
160void
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100161__jffs2_dbg_acct_paranoia_check(struct jffs2_sb_info *c,
162 struct jffs2_eraseblock *jeb)
163{
164 spin_lock(&c->erase_completion_lock);
165 __jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
166 spin_unlock(&c->erase_completion_lock);
167}
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000168
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100169void
170__jffs2_dbg_acct_paranoia_check_nolock(struct jffs2_sb_info *c,
171 struct jffs2_eraseblock *jeb)
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100172{
173 uint32_t my_used_size = 0;
174 uint32_t my_unchecked_size = 0;
175 uint32_t my_dirty_size = 0;
176 struct jffs2_raw_node_ref *ref2 = jeb->first_node;
177
178 while (ref2) {
179 uint32_t totlen = ref_totlen(c, jeb, ref2);
180
181 if (ref2->flash_offset < jeb->offset ||
182 ref2->flash_offset > jeb->offset + c->sector_size) {
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100183 JFFS2_ERROR("node_ref %#08x shouldn't be in block at %#08x.\n",
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100184 ref_offset(ref2), jeb->offset);
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100185 goto error;
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100186
187 }
188 if (ref_flags(ref2) == REF_UNCHECKED)
189 my_unchecked_size += totlen;
190 else if (!ref_obsolete(ref2))
191 my_used_size += totlen;
192 else
193 my_dirty_size += totlen;
194
195 if ((!ref2->next_phys) != (ref2 == jeb->last_node)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100196 JFFS2_ERROR("node_ref for node at %#08x (mem %p) has next_phys at %#08x (mem %p), last_node is at %#08x (mem %p).\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100197 ref_offset(ref2), ref2, ref_offset(ref2->next_phys), ref2->next_phys,
198 ref_offset(jeb->last_node), jeb->last_node);
199 goto error;
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100200 }
201 ref2 = ref2->next_phys;
202 }
203
204 if (my_used_size != jeb->used_size) {
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100205 JFFS2_ERROR("Calculated used size %#08x != stored used size %#08x.\n",
206 my_used_size, jeb->used_size);
207 goto error;
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100208 }
209
210 if (my_unchecked_size != jeb->unchecked_size) {
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100211 JFFS2_ERROR("Calculated unchecked size %#08x != stored unchecked size %#08x.\n",
212 my_unchecked_size, jeb->unchecked_size);
213 goto error;
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100214 }
215
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100216#if 0
217 /* This should work when we implement ref->__totlen elemination */
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100218 if (my_dirty_size != jeb->dirty_size + jeb->wasted_size) {
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100219 JFFS2_ERROR("Calculated dirty+wasted size %#08x != stored dirty + wasted size %#08x\n",
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100220 my_dirty_size, jeb->dirty_size + jeb->wasted_size);
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100221 goto error;
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100222 }
223
224 if (jeb->free_size == 0
225 && my_used_size + my_unchecked_size + my_dirty_size != c->sector_size) {
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100226 JFFS2_ERROR("The sum of all nodes in block (%#x) != size of block (%#x)\n",
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100227 my_used_size + my_unchecked_size + my_dirty_size,
228 c->sector_size);
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100229 goto error;
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100230 }
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100231#endif
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100232
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100233 return;
234
235error:
236 __jffs2_dbg_dump_node_refs_nolock(c, jeb);
237 __jffs2_dbg_dump_jeb_nolock(jeb);
238 __jffs2_dbg_dump_block_lists_nolock(c);
239 BUG();
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000240
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100241}
242#endif /* JFFS2_DBG_PARANOIA_CHECKS */
243
244#if defined(JFFS2_DBG_DUMPS) || defined(JFFS2_DBG_PARANOIA_CHECKS)
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100245/*
246 * Dump the node_refs of the 'jeb' JFFS2 eraseblock.
247 */
248void
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100249__jffs2_dbg_dump_node_refs(struct jffs2_sb_info *c,
250 struct jffs2_eraseblock *jeb)
251{
252 spin_lock(&c->erase_completion_lock);
253 __jffs2_dbg_dump_node_refs_nolock(c, jeb);
254 spin_unlock(&c->erase_completion_lock);
255}
256
257void
258__jffs2_dbg_dump_node_refs_nolock(struct jffs2_sb_info *c,
259 struct jffs2_eraseblock *jeb)
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100260{
261 struct jffs2_raw_node_ref *ref;
262 int i = 0;
263
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100264 printk(JFFS2_DBG_MSG_PREFIX " Dump node_refs of the eraseblock %#08x\n", jeb->offset);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100265 if (!jeb->first_node) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100266 printk(JFFS2_DBG_MSG_PREFIX " no nodes in the eraseblock %#08x\n", jeb->offset);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100267 return;
268 }
269
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100270 printk(JFFS2_DBG);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100271 for (ref = jeb->first_node; ; ref = ref->next_phys) {
272 printk("%#08x(%#x)", ref_offset(ref), ref->__totlen);
273 if (ref->next_phys)
274 printk("->");
275 else
276 break;
277 if (++i == 4) {
278 i = 0;
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100279 printk("\n" JFFS2_DBG);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100280 }
281 }
282 printk("\n");
283}
284
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100285/*
286 * Dump an eraseblock's space accounting.
287 */
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100288void
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100289__jffs2_dbg_dump_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100290{
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100291 spin_lock(&c->erase_completion_lock);
292 __jffs2_dbg_dump_jeb_nolock(jeb);
293 spin_unlock(&c->erase_completion_lock);
294}
295
296void
297__jffs2_dbg_dump_jeb_nolock(struct jffs2_eraseblock *jeb)
298{
299 if (!jeb)
300 return;
301
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100302 printk(JFFS2_DBG_MSG_PREFIX " dump space accounting for the eraseblock at %#08x:\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100303 jeb->offset);
304
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100305 printk(JFFS2_DBG "used_size: %#08x\n", jeb->used_size);
306 printk(JFFS2_DBG "dirty_size: %#08x\n", jeb->dirty_size);
307 printk(JFFS2_DBG "wasted_size: %#08x\n", jeb->wasted_size);
308 printk(JFFS2_DBG "unchecked_size: %#08x\n", jeb->unchecked_size);
309 printk(JFFS2_DBG "free_size: %#08x\n", jeb->free_size);
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100310}
311
312void
313__jffs2_dbg_dump_block_lists(struct jffs2_sb_info *c)
314{
315 spin_lock(&c->erase_completion_lock);
316 __jffs2_dbg_dump_block_lists_nolock(c);
317 spin_unlock(&c->erase_completion_lock);
318}
319
320void
321__jffs2_dbg_dump_block_lists_nolock(struct jffs2_sb_info *c)
322{
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100323 printk(JFFS2_DBG_MSG_PREFIX " dump JFFS2 blocks lists:\n");
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000324
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100325 printk(JFFS2_DBG "flash_size: %#08x\n", c->flash_size);
326 printk(JFFS2_DBG "used_size: %#08x\n", c->used_size);
327 printk(JFFS2_DBG "dirty_size: %#08x\n", c->dirty_size);
328 printk(JFFS2_DBG "wasted_size: %#08x\n", c->wasted_size);
329 printk(JFFS2_DBG "unchecked_size: %#08x\n", c->unchecked_size);
330 printk(JFFS2_DBG "free_size: %#08x\n", c->free_size);
331 printk(JFFS2_DBG "erasing_size: %#08x\n", c->erasing_size);
332 printk(JFFS2_DBG "bad_size: %#08x\n", c->bad_size);
333 printk(JFFS2_DBG "sector_size: %#08x\n", c->sector_size);
334 printk(JFFS2_DBG "jffs2_reserved_blocks size: %#08x\n",
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100335 c->sector_size * c->resv_blocks_write);
336
337 if (c->nextblock)
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100338 printk(JFFS2_DBG "nextblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100339 c->nextblock->offset, c->nextblock->used_size,
340 c->nextblock->dirty_size, c->nextblock->wasted_size,
341 c->nextblock->unchecked_size, c->nextblock->free_size);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100342 else
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100343 printk(JFFS2_DBG "nextblock: NULL\n");
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100344
345 if (c->gcblock)
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100346 printk(JFFS2_DBG "gcblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100347 c->gcblock->offset, c->gcblock->used_size, c->gcblock->dirty_size,
348 c->gcblock->wasted_size, c->gcblock->unchecked_size, c->gcblock->free_size);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100349 else
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100350 printk(JFFS2_DBG "gcblock: NULL\n");
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100351
352 if (list_empty(&c->clean_list)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100353 printk(JFFS2_DBG "clean_list: empty\n");
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100354 } else {
355 struct list_head *this;
356 int numblocks = 0;
357 uint32_t dirty = 0;
358
359 list_for_each(this, &c->clean_list) {
360 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
361 numblocks ++;
362 dirty += jeb->wasted_size;
363 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100364 printk(JFFS2_DBG "clean_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100365 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
366 jeb->unchecked_size, jeb->free_size);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100367 }
368 }
369
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100370 printk (JFFS2_DBG "Contains %d blocks with total wasted size %u, average wasted size: %u\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100371 numblocks, dirty, dirty / numblocks);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100372 }
373
374 if (list_empty(&c->very_dirty_list)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100375 printk(JFFS2_DBG "very_dirty_list: empty\n");
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100376 } else {
377 struct list_head *this;
378 int numblocks = 0;
379 uint32_t dirty = 0;
380
381 list_for_each(this, &c->very_dirty_list) {
382 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
383
384 numblocks ++;
385 dirty += jeb->dirty_size;
386 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100387 printk(JFFS2_DBG "very_dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100388 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
389 jeb->unchecked_size, jeb->free_size);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100390 }
391 }
392
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100393 printk (JFFS2_DBG "Contains %d blocks with total dirty size %u, average dirty size: %u\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100394 numblocks, dirty, dirty / numblocks);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100395 }
396
397 if (list_empty(&c->dirty_list)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100398 printk(JFFS2_DBG "dirty_list: empty\n");
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100399 } else {
400 struct list_head *this;
401 int numblocks = 0;
402 uint32_t dirty = 0;
403
404 list_for_each(this, &c->dirty_list) {
405 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
406
407 numblocks ++;
408 dirty += jeb->dirty_size;
409 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100410 printk(JFFS2_DBG "dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100411 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
412 jeb->unchecked_size, jeb->free_size);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100413 }
414 }
415
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100416 printk (JFFS2_DBG "contains %d blocks with total dirty size %u, average dirty size: %u\n",
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100417 numblocks, dirty, dirty / numblocks);
418 }
419
420 if (list_empty(&c->erasable_list)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100421 printk(JFFS2_DBG "erasable_list: empty\n");
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100422 } else {
423 struct list_head *this;
424
425 list_for_each(this, &c->erasable_list) {
426 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
427
428 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100429 printk(JFFS2_DBG "erasable_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100430 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
431 jeb->unchecked_size, jeb->free_size);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100432 }
433 }
434 }
435
436 if (list_empty(&c->erasing_list)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100437 printk(JFFS2_DBG "erasing_list: empty\n");
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100438 } else {
439 struct list_head *this;
440
441 list_for_each(this, &c->erasing_list) {
442 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
443
444 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100445 printk(JFFS2_DBG "erasing_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100446 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
447 jeb->unchecked_size, jeb->free_size);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100448 }
449 }
450 }
451
452 if (list_empty(&c->erase_pending_list)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100453 printk(JFFS2_DBG "erase_pending_list: empty\n");
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100454 } else {
455 struct list_head *this;
456
457 list_for_each(this, &c->erase_pending_list) {
458 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
459
460 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100461 printk(JFFS2_DBG "erase_pending_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100462 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
463 jeb->unchecked_size, jeb->free_size);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100464 }
465 }
466 }
467
468 if (list_empty(&c->erasable_pending_wbuf_list)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100469 printk(JFFS2_DBG "erasable_pending_wbuf_list: empty\n");
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100470 } else {
471 struct list_head *this;
472
473 list_for_each(this, &c->erasable_pending_wbuf_list) {
474 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
475
476 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100477 printk(JFFS2_DBG "erasable_pending_wbuf_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100478 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
479 jeb->unchecked_size, jeb->free_size);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100480 }
481 }
482 }
483
484 if (list_empty(&c->free_list)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100485 printk(JFFS2_DBG "free_list: empty\n");
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100486 } else {
487 struct list_head *this;
488
489 list_for_each(this, &c->free_list) {
490 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
491
492 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100493 printk(JFFS2_DBG "free_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100494 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
495 jeb->unchecked_size, jeb->free_size);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100496 }
497 }
498 }
499
500 if (list_empty(&c->bad_list)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100501 printk(JFFS2_DBG "bad_list: empty\n");
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100502 } else {
503 struct list_head *this;
504
505 list_for_each(this, &c->bad_list) {
506 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
507
508 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100509 printk(JFFS2_DBG "bad_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100510 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
511 jeb->unchecked_size, jeb->free_size);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100512 }
513 }
514 }
515
516 if (list_empty(&c->bad_used_list)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100517 printk(JFFS2_DBG "bad_used_list: empty\n");
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100518 } else {
519 struct list_head *this;
520
521 list_for_each(this, &c->bad_used_list) {
522 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
523
524 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100525 printk(JFFS2_DBG "bad_used_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100526 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
527 jeb->unchecked_size, jeb->free_size);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100528 }
529 }
530 }
531}
532
533void
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100534__jffs2_dbg_dump_fragtree(struct jffs2_inode_info *f)
535{
536 down(&f->sem);
537 jffs2_dbg_dump_fragtree_nolock(f);
538 up(&f->sem);
539}
540
541void
542__jffs2_dbg_dump_fragtree_nolock(struct jffs2_inode_info *f)
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100543{
544 struct jffs2_node_frag *this = frag_first(&f->fragtree);
545 uint32_t lastofs = 0;
546 int buggy = 0;
547
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100548 printk(JFFS2_DBG_MSG_PREFIX " dump fragtree of ino #%u\n", f->inocache->ino);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100549 while(this) {
550 if (this->node)
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100551 printk(JFFS2_DBG "frag %#04x-%#04x: %#08x(%d) on flash (*%p), left (%p), right (%p), parent (%p)\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100552 this->ofs, this->ofs+this->size, ref_offset(this->node->raw),
553 ref_flags(this->node->raw), this, frag_left(this), frag_right(this),
554 frag_parent(this));
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100555 else
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100556 printk(JFFS2_DBG "frag %#04x-%#04x: hole (*%p). left (%p), right (%p), parent (%p)\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100557 this->ofs, this->ofs+this->size, this, frag_left(this),
558 frag_right(this), frag_parent(this));
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100559 if (this->ofs != lastofs)
560 buggy = 1;
561 lastofs = this->ofs + this->size;
562 this = frag_next(this);
563 }
564
565 if (f->metadata)
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100566 printk(JFFS2_DBG "metadata at 0x%08x\n", ref_offset(f->metadata->raw));
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100567
568 if (buggy) {
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100569 JFFS2_ERROR("frag tree got a hole in it.\n");
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100570 BUG();
571 }
572}
573
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100574#define JFFS2_BUFDUMP_BYTES_PER_LINE 32
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100575void
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100576__jffs2_dbg_dump_buffer(unsigned char *buf, int len, uint32_t offs)
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100577{
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100578 int skip;
579 int i;
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000580
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100581 printk(JFFS2_DBG_MSG_PREFIX " dump from offset %#08x to offset %#08x (%x bytes).\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100582 offs, offs + len, len);
583 i = skip = offs % JFFS2_BUFDUMP_BYTES_PER_LINE;
584 offs = offs & ~(JFFS2_BUFDUMP_BYTES_PER_LINE - 1);
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000585
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100586 if (skip != 0)
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100587 printk(JFFS2_DBG "%#08x: ", offs);
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000588
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100589 while (skip--)
590 printk(" ");
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100591
592 while (i < len) {
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100593 if ((i % JFFS2_BUFDUMP_BYTES_PER_LINE) == 0 && i != len -1) {
594 if (i != 0)
595 printk("\n");
596 offs += JFFS2_BUFDUMP_BYTES_PER_LINE;
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100597 printk(JFFS2_DBG "%0#8x: ", offs);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100598 }
599
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100600 printk("%02x ", buf[i]);
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000601
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100602 i += 1;
603 }
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100604
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100605 printk("\n");
606}
607
608/*
609 * Dump a JFFS2 node.
610 */
611void
612__jffs2_dbg_dump_node(struct jffs2_sb_info *c, uint32_t ofs)
613{
614 union jffs2_node_union node;
615 int len = sizeof(union jffs2_node_union);
616 size_t retlen;
617 uint32_t crc;
618 int ret;
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000619
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100620 printk(JFFS2_DBG_MSG_PREFIX " dump node at offset %#08x.\n", ofs);
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100621
622 ret = jffs2_flash_read(c, ofs, len, &retlen, (unsigned char *)&node);
623 if (ret || (retlen != len)) {
624 JFFS2_ERROR("read %d bytes failed or short. ret %d, retlen %zd.\n",
625 len, ret, retlen);
626 return;
627 }
628
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100629 printk(JFFS2_DBG "magic:\t%#04x\n", je16_to_cpu(node.u.magic));
630 printk(JFFS2_DBG "nodetype:\t%#04x\n", je16_to_cpu(node.u.nodetype));
631 printk(JFFS2_DBG "totlen:\t%#08x\n", je32_to_cpu(node.u.totlen));
632 printk(JFFS2_DBG "hdr_crc:\t%#08x\n", je32_to_cpu(node.u.hdr_crc));
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000633
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100634 crc = crc32(0, &node.u, sizeof(node.u) - 4);
635 if (crc != je32_to_cpu(node.u.hdr_crc)) {
636 JFFS2_ERROR("wrong common header CRC.\n");
637 return;
638 }
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000639
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100640 if (je16_to_cpu(node.u.magic) != JFFS2_MAGIC_BITMASK &&
641 je16_to_cpu(node.u.magic) != JFFS2_OLD_MAGIC_BITMASK)
642 {
643 JFFS2_ERROR("wrong node magic: %#04x instead of %#04x.\n",
644 je16_to_cpu(node.u.magic), JFFS2_MAGIC_BITMASK);
645 return;
646 }
647
648 switch(je16_to_cpu(node.u.nodetype)) {
649
650 case JFFS2_NODETYPE_INODE:
651
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100652 printk(JFFS2_DBG "the node is inode node\n");
653 printk(JFFS2_DBG "ino:\t%#08x\n", je32_to_cpu(node.i.ino));
654 printk(JFFS2_DBG "version:\t%#08x\n", je32_to_cpu(node.i.version));
655 printk(JFFS2_DBG "mode:\t%#08x\n", node.i.mode.m);
656 printk(JFFS2_DBG "uid:\t%#04x\n", je16_to_cpu(node.i.uid));
657 printk(JFFS2_DBG "gid:\t%#04x\n", je16_to_cpu(node.i.gid));
658 printk(JFFS2_DBG "isize:\t%#08x\n", je32_to_cpu(node.i.isize));
659 printk(JFFS2_DBG "atime:\t%#08x\n", je32_to_cpu(node.i.atime));
660 printk(JFFS2_DBG "mtime:\t%#08x\n", je32_to_cpu(node.i.mtime));
661 printk(JFFS2_DBG "ctime:\t%#08x\n", je32_to_cpu(node.i.ctime));
662 printk(JFFS2_DBG "offset:\t%#08x\n", je32_to_cpu(node.i.offset));
663 printk(JFFS2_DBG "csize:\t%#08x\n", je32_to_cpu(node.i.csize));
664 printk(JFFS2_DBG "dsize:\t%#08x\n", je32_to_cpu(node.i.dsize));
665 printk(JFFS2_DBG "compr:\t%#02x\n", node.i.compr);
666 printk(JFFS2_DBG "usercompr:\t%#02x\n", node.i.usercompr);
667 printk(JFFS2_DBG "flags:\t%#04x\n", je16_to_cpu(node.i.flags));
668 printk(JFFS2_DBG "data_crc:\t%#08x\n", je32_to_cpu(node.i.data_crc));
669 printk(JFFS2_DBG "node_crc:\t%#08x\n", je32_to_cpu(node.i.node_crc));
670
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000671 crc = crc32(0, &node.i, sizeof(node.i) - 8);
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100672 if (crc != je32_to_cpu(node.i.node_crc)) {
673 JFFS2_ERROR("wrong node header CRC.\n");
674 return;
675 }
676 break;
677
678 case JFFS2_NODETYPE_DIRENT:
679
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100680 printk(JFFS2_DBG "the node is dirent node\n");
681 printk(JFFS2_DBG "pino:\t%#08x\n", je32_to_cpu(node.d.pino));
682 printk(JFFS2_DBG "version:\t%#08x\n", je32_to_cpu(node.d.version));
683 printk(JFFS2_DBG "ino:\t%#08x\n", je32_to_cpu(node.d.ino));
684 printk(JFFS2_DBG "mctime:\t%#08x\n", je32_to_cpu(node.d.mctime));
685 printk(JFFS2_DBG "nsize:\t%#02x\n", node.d.nsize);
686 printk(JFFS2_DBG "type:\t%#02x\n", node.d.type);
687 printk(JFFS2_DBG "node_crc:\t%#08x\n", je32_to_cpu(node.d.node_crc));
688 printk(JFFS2_DBG "name_crc:\t%#08x\n", je32_to_cpu(node.d.name_crc));
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000689
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100690 node.d.name[node.d.nsize] = '\0';
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100691 printk(JFFS2_DBG "name:\t\"%s\"\n", node.d.name);
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100692
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000693 crc = crc32(0, &node.d, sizeof(node.d) - 8);
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100694 if (crc != je32_to_cpu(node.d.node_crc)) {
695 JFFS2_ERROR("wrong node header CRC.\n");
696 return;
697 }
698 break;
699
700 default:
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100701 printk(JFFS2_DBG "node type is unknown\n");
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100702 break;
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100703 }
704}
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100705#endif /* JFFS2_DBG_DUMPS || JFFS2_DBG_PARANOIA_CHECKS */