Linux 2.6.24-rc8
[pv_ops_mirror.git] / fs / jffs2 / debug.c
blob3a32c64ed4975260079e7b9f3c435eecef18b534
1 /*
2 * JFFS2 -- Journalling Flash File System, Version 2.
4 * Copyright © 2001-2007 Red Hat, Inc.
6 * Created by David Woodhouse <dwmw2@infradead.org>
8 * For licensing information, see the file 'LICENCE' in this directory.
12 #include <linux/kernel.h>
13 #include <linux/types.h>
14 #include <linux/pagemap.h>
15 #include <linux/crc32.h>
16 #include <linux/jffs2.h>
17 #include <linux/mtd/mtd.h>
18 #include "nodelist.h"
19 #include "debug.h"
21 #ifdef JFFS2_DBG_SANITY_CHECKS
23 void
24 __jffs2_dbg_acct_sanity_check_nolock(struct jffs2_sb_info *c,
25 struct jffs2_eraseblock *jeb)
27 if (unlikely(jeb && jeb->used_size + jeb->dirty_size +
28 jeb->free_size + jeb->wasted_size +
29 jeb->unchecked_size != c->sector_size)) {
30 JFFS2_ERROR("eeep, space accounting for block at 0x%08x is screwed.\n", jeb->offset);
31 JFFS2_ERROR("free %#08x + dirty %#08x + used %#08x + wasted %#08x + unchecked %#08x != total %#08x.\n",
32 jeb->free_size, jeb->dirty_size, jeb->used_size,
33 jeb->wasted_size, jeb->unchecked_size, c->sector_size);
34 BUG();
37 if (unlikely(c->used_size + c->dirty_size + c->free_size + c->erasing_size + c->bad_size
38 + c->wasted_size + c->unchecked_size != c->flash_size)) {
39 JFFS2_ERROR("eeep, space accounting superblock info is screwed.\n");
40 JFFS2_ERROR("free %#08x + dirty %#08x + used %#08x + erasing %#08x + bad %#08x + wasted %#08x + unchecked %#08x != total %#08x.\n",
41 c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size,
42 c->wasted_size, c->unchecked_size, c->flash_size);
43 BUG();
47 void
48 __jffs2_dbg_acct_sanity_check(struct jffs2_sb_info *c,
49 struct jffs2_eraseblock *jeb)
51 spin_lock(&c->erase_completion_lock);
52 jffs2_dbg_acct_sanity_check_nolock(c, jeb);
53 spin_unlock(&c->erase_completion_lock);
56 #endif /* JFFS2_DBG_SANITY_CHECKS */
58 #ifdef JFFS2_DBG_PARANOIA_CHECKS
60 * Check the fragtree.
62 void
63 __jffs2_dbg_fragtree_paranoia_check(struct jffs2_inode_info *f)
65 down(&f->sem);
66 __jffs2_dbg_fragtree_paranoia_check_nolock(f);
67 up(&f->sem);
70 void
71 __jffs2_dbg_fragtree_paranoia_check_nolock(struct jffs2_inode_info *f)
73 struct jffs2_node_frag *frag;
74 int bitched = 0;
76 for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) {
77 struct jffs2_full_dnode *fn = frag->node;
79 if (!fn || !fn->raw)
80 continue;
82 if (ref_flags(fn->raw) == REF_PRISTINE) {
83 if (fn->frags > 1) {
84 JFFS2_ERROR("REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2.\n",
85 ref_offset(fn->raw), fn->frags);
86 bitched = 1;
89 /* A hole node which isn't multi-page should be garbage-collected
90 and merged anyway, so we just check for the frag size here,
91 rather than mucking around with actually reading the node
92 and checking the compression type, which is the real way
93 to tell a hole node. */
94 if (frag->ofs & (PAGE_CACHE_SIZE-1) && frag_prev(frag)
95 && frag_prev(frag)->size < PAGE_CACHE_SIZE && frag_prev(frag)->node) {
96 JFFS2_ERROR("REF_PRISTINE node at 0x%08x had a previous non-hole frag in the same page. Tell dwmw2.\n",
97 ref_offset(fn->raw));
98 bitched = 1;
101 if ((frag->ofs+frag->size) & (PAGE_CACHE_SIZE-1) && frag_next(frag)
102 && frag_next(frag)->size < PAGE_CACHE_SIZE && frag_next(frag)->node) {
103 JFFS2_ERROR("REF_PRISTINE node at 0x%08x (%08x-%08x) had a following non-hole frag in the same page. Tell dwmw2.\n",
104 ref_offset(fn->raw), frag->ofs, frag->ofs+frag->size);
105 bitched = 1;
110 if (bitched) {
111 JFFS2_ERROR("fragtree is corrupted.\n");
112 __jffs2_dbg_dump_fragtree_nolock(f);
113 BUG();
118 * Check if the flash contains all 0xFF before we start writing.
120 void
121 __jffs2_dbg_prewrite_paranoia_check(struct jffs2_sb_info *c,
122 uint32_t ofs, int len)
124 size_t retlen;
125 int ret, i;
126 unsigned char *buf;
128 buf = kmalloc(len, GFP_KERNEL);
129 if (!buf)
130 return;
132 ret = jffs2_flash_read(c, ofs, len, &retlen, buf);
133 if (ret || (retlen != len)) {
134 JFFS2_WARNING("read %d bytes failed or short. ret %d, retlen %zd.\n",
135 len, ret, retlen);
136 kfree(buf);
137 return;
140 ret = 0;
141 for (i = 0; i < len; i++)
142 if (buf[i] != 0xff)
143 ret = 1;
145 if (ret) {
146 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",
147 ofs, ofs + i);
148 __jffs2_dbg_dump_buffer(buf, len, ofs);
149 kfree(buf);
150 BUG();
153 kfree(buf);
157 * Check the space accounting and node_ref list correctness for the JFFS2 erasable block 'jeb'.
159 void
160 __jffs2_dbg_acct_paranoia_check(struct jffs2_sb_info *c,
161 struct jffs2_eraseblock *jeb)
163 spin_lock(&c->erase_completion_lock);
164 __jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
165 spin_unlock(&c->erase_completion_lock);
168 void
169 __jffs2_dbg_acct_paranoia_check_nolock(struct jffs2_sb_info *c,
170 struct jffs2_eraseblock *jeb)
172 uint32_t my_used_size = 0;
173 uint32_t my_unchecked_size = 0;
174 uint32_t my_dirty_size = 0;
175 struct jffs2_raw_node_ref *ref2 = jeb->first_node;
177 while (ref2) {
178 uint32_t totlen = ref_totlen(c, jeb, ref2);
180 if (ref_offset(ref2) < jeb->offset ||
181 ref_offset(ref2) > jeb->offset + c->sector_size) {
182 JFFS2_ERROR("node_ref %#08x shouldn't be in block at %#08x.\n",
183 ref_offset(ref2), jeb->offset);
184 goto error;
187 if (ref_flags(ref2) == REF_UNCHECKED)
188 my_unchecked_size += totlen;
189 else if (!ref_obsolete(ref2))
190 my_used_size += totlen;
191 else
192 my_dirty_size += totlen;
194 if ((!ref_next(ref2)) != (ref2 == jeb->last_node)) {
195 JFFS2_ERROR("node_ref for node at %#08x (mem %p) has next at %#08x (mem %p), last_node is at %#08x (mem %p).\n",
196 ref_offset(ref2), ref2, ref_offset(ref_next(ref2)), ref_next(ref2),
197 ref_offset(jeb->last_node), jeb->last_node);
198 goto error;
200 ref2 = ref_next(ref2);
203 if (my_used_size != jeb->used_size) {
204 JFFS2_ERROR("Calculated used size %#08x != stored used size %#08x.\n",
205 my_used_size, jeb->used_size);
206 goto error;
209 if (my_unchecked_size != jeb->unchecked_size) {
210 JFFS2_ERROR("Calculated unchecked size %#08x != stored unchecked size %#08x.\n",
211 my_unchecked_size, jeb->unchecked_size);
212 goto error;
215 #if 0
216 /* This should work when we implement ref->__totlen elemination */
217 if (my_dirty_size != jeb->dirty_size + jeb->wasted_size) {
218 JFFS2_ERROR("Calculated dirty+wasted size %#08x != stored dirty + wasted size %#08x\n",
219 my_dirty_size, jeb->dirty_size + jeb->wasted_size);
220 goto error;
223 if (jeb->free_size == 0
224 && my_used_size + my_unchecked_size + my_dirty_size != c->sector_size) {
225 JFFS2_ERROR("The sum of all nodes in block (%#x) != size of block (%#x)\n",
226 my_used_size + my_unchecked_size + my_dirty_size,
227 c->sector_size);
228 goto error;
230 #endif
232 return;
234 error:
235 __jffs2_dbg_dump_node_refs_nolock(c, jeb);
236 __jffs2_dbg_dump_jeb_nolock(jeb);
237 __jffs2_dbg_dump_block_lists_nolock(c);
238 BUG();
241 #endif /* JFFS2_DBG_PARANOIA_CHECKS */
243 #if defined(JFFS2_DBG_DUMPS) || defined(JFFS2_DBG_PARANOIA_CHECKS)
245 * Dump the node_refs of the 'jeb' JFFS2 eraseblock.
247 void
248 __jffs2_dbg_dump_node_refs(struct jffs2_sb_info *c,
249 struct jffs2_eraseblock *jeb)
251 spin_lock(&c->erase_completion_lock);
252 __jffs2_dbg_dump_node_refs_nolock(c, jeb);
253 spin_unlock(&c->erase_completion_lock);
256 void
257 __jffs2_dbg_dump_node_refs_nolock(struct jffs2_sb_info *c,
258 struct jffs2_eraseblock *jeb)
260 struct jffs2_raw_node_ref *ref;
261 int i = 0;
263 printk(JFFS2_DBG_MSG_PREFIX " Dump node_refs of the eraseblock %#08x\n", jeb->offset);
264 if (!jeb->first_node) {
265 printk(JFFS2_DBG_MSG_PREFIX " no nodes in the eraseblock %#08x\n", jeb->offset);
266 return;
269 printk(JFFS2_DBG);
270 for (ref = jeb->first_node; ; ref = ref_next(ref)) {
271 printk("%#08x(%#x)", ref_offset(ref), ref->__totlen);
272 if (ref_next(ref))
273 printk("->");
274 else
275 break;
276 if (++i == 4) {
277 i = 0;
278 printk("\n" JFFS2_DBG);
281 printk("\n");
285 * Dump an eraseblock's space accounting.
287 void
288 __jffs2_dbg_dump_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
290 spin_lock(&c->erase_completion_lock);
291 __jffs2_dbg_dump_jeb_nolock(jeb);
292 spin_unlock(&c->erase_completion_lock);
295 void
296 __jffs2_dbg_dump_jeb_nolock(struct jffs2_eraseblock *jeb)
298 if (!jeb)
299 return;
301 printk(JFFS2_DBG_MSG_PREFIX " dump space accounting for the eraseblock at %#08x:\n",
302 jeb->offset);
304 printk(JFFS2_DBG "used_size: %#08x\n", jeb->used_size);
305 printk(JFFS2_DBG "dirty_size: %#08x\n", jeb->dirty_size);
306 printk(JFFS2_DBG "wasted_size: %#08x\n", jeb->wasted_size);
307 printk(JFFS2_DBG "unchecked_size: %#08x\n", jeb->unchecked_size);
308 printk(JFFS2_DBG "free_size: %#08x\n", jeb->free_size);
311 void
312 __jffs2_dbg_dump_block_lists(struct jffs2_sb_info *c)
314 spin_lock(&c->erase_completion_lock);
315 __jffs2_dbg_dump_block_lists_nolock(c);
316 spin_unlock(&c->erase_completion_lock);
319 void
320 __jffs2_dbg_dump_block_lists_nolock(struct jffs2_sb_info *c)
322 printk(JFFS2_DBG_MSG_PREFIX " dump JFFS2 blocks lists:\n");
324 printk(JFFS2_DBG "flash_size: %#08x\n", c->flash_size);
325 printk(JFFS2_DBG "used_size: %#08x\n", c->used_size);
326 printk(JFFS2_DBG "dirty_size: %#08x\n", c->dirty_size);
327 printk(JFFS2_DBG "wasted_size: %#08x\n", c->wasted_size);
328 printk(JFFS2_DBG "unchecked_size: %#08x\n", c->unchecked_size);
329 printk(JFFS2_DBG "free_size: %#08x\n", c->free_size);
330 printk(JFFS2_DBG "erasing_size: %#08x\n", c->erasing_size);
331 printk(JFFS2_DBG "bad_size: %#08x\n", c->bad_size);
332 printk(JFFS2_DBG "sector_size: %#08x\n", c->sector_size);
333 printk(JFFS2_DBG "jffs2_reserved_blocks size: %#08x\n",
334 c->sector_size * c->resv_blocks_write);
336 if (c->nextblock)
337 printk(JFFS2_DBG "nextblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
338 c->nextblock->offset, c->nextblock->used_size,
339 c->nextblock->dirty_size, c->nextblock->wasted_size,
340 c->nextblock->unchecked_size, c->nextblock->free_size);
341 else
342 printk(JFFS2_DBG "nextblock: NULL\n");
344 if (c->gcblock)
345 printk(JFFS2_DBG "gcblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
346 c->gcblock->offset, c->gcblock->used_size, c->gcblock->dirty_size,
347 c->gcblock->wasted_size, c->gcblock->unchecked_size, c->gcblock->free_size);
348 else
349 printk(JFFS2_DBG "gcblock: NULL\n");
351 if (list_empty(&c->clean_list)) {
352 printk(JFFS2_DBG "clean_list: empty\n");
353 } else {
354 struct list_head *this;
355 int numblocks = 0;
356 uint32_t dirty = 0;
358 list_for_each(this, &c->clean_list) {
359 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
360 numblocks ++;
361 dirty += jeb->wasted_size;
362 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
363 printk(JFFS2_DBG "clean_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
364 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
365 jeb->unchecked_size, jeb->free_size);
369 printk (JFFS2_DBG "Contains %d blocks with total wasted size %u, average wasted size: %u\n",
370 numblocks, dirty, dirty / numblocks);
373 if (list_empty(&c->very_dirty_list)) {
374 printk(JFFS2_DBG "very_dirty_list: empty\n");
375 } else {
376 struct list_head *this;
377 int numblocks = 0;
378 uint32_t dirty = 0;
380 list_for_each(this, &c->very_dirty_list) {
381 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
383 numblocks ++;
384 dirty += jeb->dirty_size;
385 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
386 printk(JFFS2_DBG "very_dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
387 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
388 jeb->unchecked_size, jeb->free_size);
392 printk (JFFS2_DBG "Contains %d blocks with total dirty size %u, average dirty size: %u\n",
393 numblocks, dirty, dirty / numblocks);
396 if (list_empty(&c->dirty_list)) {
397 printk(JFFS2_DBG "dirty_list: empty\n");
398 } else {
399 struct list_head *this;
400 int numblocks = 0;
401 uint32_t dirty = 0;
403 list_for_each(this, &c->dirty_list) {
404 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
406 numblocks ++;
407 dirty += jeb->dirty_size;
408 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
409 printk(JFFS2_DBG "dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
410 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
411 jeb->unchecked_size, jeb->free_size);
415 printk (JFFS2_DBG "contains %d blocks with total dirty size %u, average dirty size: %u\n",
416 numblocks, dirty, dirty / numblocks);
419 if (list_empty(&c->erasable_list)) {
420 printk(JFFS2_DBG "erasable_list: empty\n");
421 } else {
422 struct list_head *this;
424 list_for_each(this, &c->erasable_list) {
425 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
427 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
428 printk(JFFS2_DBG "erasable_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
429 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
430 jeb->unchecked_size, jeb->free_size);
435 if (list_empty(&c->erasing_list)) {
436 printk(JFFS2_DBG "erasing_list: empty\n");
437 } else {
438 struct list_head *this;
440 list_for_each(this, &c->erasing_list) {
441 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
443 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
444 printk(JFFS2_DBG "erasing_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
445 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
446 jeb->unchecked_size, jeb->free_size);
451 if (list_empty(&c->erase_pending_list)) {
452 printk(JFFS2_DBG "erase_pending_list: empty\n");
453 } else {
454 struct list_head *this;
456 list_for_each(this, &c->erase_pending_list) {
457 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
459 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
460 printk(JFFS2_DBG "erase_pending_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
461 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
462 jeb->unchecked_size, jeb->free_size);
467 if (list_empty(&c->erasable_pending_wbuf_list)) {
468 printk(JFFS2_DBG "erasable_pending_wbuf_list: empty\n");
469 } else {
470 struct list_head *this;
472 list_for_each(this, &c->erasable_pending_wbuf_list) {
473 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
475 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
476 printk(JFFS2_DBG "erasable_pending_wbuf_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
477 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
478 jeb->unchecked_size, jeb->free_size);
483 if (list_empty(&c->free_list)) {
484 printk(JFFS2_DBG "free_list: empty\n");
485 } else {
486 struct list_head *this;
488 list_for_each(this, &c->free_list) {
489 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
491 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
492 printk(JFFS2_DBG "free_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
493 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
494 jeb->unchecked_size, jeb->free_size);
499 if (list_empty(&c->bad_list)) {
500 printk(JFFS2_DBG "bad_list: empty\n");
501 } else {
502 struct list_head *this;
504 list_for_each(this, &c->bad_list) {
505 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
507 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
508 printk(JFFS2_DBG "bad_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
509 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
510 jeb->unchecked_size, jeb->free_size);
515 if (list_empty(&c->bad_used_list)) {
516 printk(JFFS2_DBG "bad_used_list: empty\n");
517 } else {
518 struct list_head *this;
520 list_for_each(this, &c->bad_used_list) {
521 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
523 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
524 printk(JFFS2_DBG "bad_used_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
525 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
526 jeb->unchecked_size, jeb->free_size);
532 void
533 __jffs2_dbg_dump_fragtree(struct jffs2_inode_info *f)
535 down(&f->sem);
536 jffs2_dbg_dump_fragtree_nolock(f);
537 up(&f->sem);
540 void
541 __jffs2_dbg_dump_fragtree_nolock(struct jffs2_inode_info *f)
543 struct jffs2_node_frag *this = frag_first(&f->fragtree);
544 uint32_t lastofs = 0;
545 int buggy = 0;
547 printk(JFFS2_DBG_MSG_PREFIX " dump fragtree of ino #%u\n", f->inocache->ino);
548 while(this) {
549 if (this->node)
550 printk(JFFS2_DBG "frag %#04x-%#04x: %#08x(%d) on flash (*%p), left (%p), right (%p), parent (%p)\n",
551 this->ofs, this->ofs+this->size, ref_offset(this->node->raw),
552 ref_flags(this->node->raw), this, frag_left(this), frag_right(this),
553 frag_parent(this));
554 else
555 printk(JFFS2_DBG "frag %#04x-%#04x: hole (*%p). left (%p), right (%p), parent (%p)\n",
556 this->ofs, this->ofs+this->size, this, frag_left(this),
557 frag_right(this), frag_parent(this));
558 if (this->ofs != lastofs)
559 buggy = 1;
560 lastofs = this->ofs + this->size;
561 this = frag_next(this);
564 if (f->metadata)
565 printk(JFFS2_DBG "metadata at 0x%08x\n", ref_offset(f->metadata->raw));
567 if (buggy) {
568 JFFS2_ERROR("frag tree got a hole in it.\n");
569 BUG();
573 #define JFFS2_BUFDUMP_BYTES_PER_LINE 32
574 void
575 __jffs2_dbg_dump_buffer(unsigned char *buf, int len, uint32_t offs)
577 int skip;
578 int i;
580 printk(JFFS2_DBG_MSG_PREFIX " dump from offset %#08x to offset %#08x (%x bytes).\n",
581 offs, offs + len, len);
582 i = skip = offs % JFFS2_BUFDUMP_BYTES_PER_LINE;
583 offs = offs & ~(JFFS2_BUFDUMP_BYTES_PER_LINE - 1);
585 if (skip != 0)
586 printk(JFFS2_DBG "%#08x: ", offs);
588 while (skip--)
589 printk(" ");
591 while (i < len) {
592 if ((i % JFFS2_BUFDUMP_BYTES_PER_LINE) == 0 && i != len -1) {
593 if (i != 0)
594 printk("\n");
595 offs += JFFS2_BUFDUMP_BYTES_PER_LINE;
596 printk(JFFS2_DBG "%0#8x: ", offs);
599 printk("%02x ", buf[i]);
601 i += 1;
604 printk("\n");
608 * Dump a JFFS2 node.
610 void
611 __jffs2_dbg_dump_node(struct jffs2_sb_info *c, uint32_t ofs)
613 union jffs2_node_union node;
614 int len = sizeof(union jffs2_node_union);
615 size_t retlen;
616 uint32_t crc;
617 int ret;
619 printk(JFFS2_DBG_MSG_PREFIX " dump node at offset %#08x.\n", ofs);
621 ret = jffs2_flash_read(c, ofs, len, &retlen, (unsigned char *)&node);
622 if (ret || (retlen != len)) {
623 JFFS2_ERROR("read %d bytes failed or short. ret %d, retlen %zd.\n",
624 len, ret, retlen);
625 return;
628 printk(JFFS2_DBG "magic:\t%#04x\n", je16_to_cpu(node.u.magic));
629 printk(JFFS2_DBG "nodetype:\t%#04x\n", je16_to_cpu(node.u.nodetype));
630 printk(JFFS2_DBG "totlen:\t%#08x\n", je32_to_cpu(node.u.totlen));
631 printk(JFFS2_DBG "hdr_crc:\t%#08x\n", je32_to_cpu(node.u.hdr_crc));
633 crc = crc32(0, &node.u, sizeof(node.u) - 4);
634 if (crc != je32_to_cpu(node.u.hdr_crc)) {
635 JFFS2_ERROR("wrong common header CRC.\n");
636 return;
639 if (je16_to_cpu(node.u.magic) != JFFS2_MAGIC_BITMASK &&
640 je16_to_cpu(node.u.magic) != JFFS2_OLD_MAGIC_BITMASK)
642 JFFS2_ERROR("wrong node magic: %#04x instead of %#04x.\n",
643 je16_to_cpu(node.u.magic), JFFS2_MAGIC_BITMASK);
644 return;
647 switch(je16_to_cpu(node.u.nodetype)) {
649 case JFFS2_NODETYPE_INODE:
651 printk(JFFS2_DBG "the node is inode node\n");
652 printk(JFFS2_DBG "ino:\t%#08x\n", je32_to_cpu(node.i.ino));
653 printk(JFFS2_DBG "version:\t%#08x\n", je32_to_cpu(node.i.version));
654 printk(JFFS2_DBG "mode:\t%#08x\n", node.i.mode.m);
655 printk(JFFS2_DBG "uid:\t%#04x\n", je16_to_cpu(node.i.uid));
656 printk(JFFS2_DBG "gid:\t%#04x\n", je16_to_cpu(node.i.gid));
657 printk(JFFS2_DBG "isize:\t%#08x\n", je32_to_cpu(node.i.isize));
658 printk(JFFS2_DBG "atime:\t%#08x\n", je32_to_cpu(node.i.atime));
659 printk(JFFS2_DBG "mtime:\t%#08x\n", je32_to_cpu(node.i.mtime));
660 printk(JFFS2_DBG "ctime:\t%#08x\n", je32_to_cpu(node.i.ctime));
661 printk(JFFS2_DBG "offset:\t%#08x\n", je32_to_cpu(node.i.offset));
662 printk(JFFS2_DBG "csize:\t%#08x\n", je32_to_cpu(node.i.csize));
663 printk(JFFS2_DBG "dsize:\t%#08x\n", je32_to_cpu(node.i.dsize));
664 printk(JFFS2_DBG "compr:\t%#02x\n", node.i.compr);
665 printk(JFFS2_DBG "usercompr:\t%#02x\n", node.i.usercompr);
666 printk(JFFS2_DBG "flags:\t%#04x\n", je16_to_cpu(node.i.flags));
667 printk(JFFS2_DBG "data_crc:\t%#08x\n", je32_to_cpu(node.i.data_crc));
668 printk(JFFS2_DBG "node_crc:\t%#08x\n", je32_to_cpu(node.i.node_crc));
670 crc = crc32(0, &node.i, sizeof(node.i) - 8);
671 if (crc != je32_to_cpu(node.i.node_crc)) {
672 JFFS2_ERROR("wrong node header CRC.\n");
673 return;
675 break;
677 case JFFS2_NODETYPE_DIRENT:
679 printk(JFFS2_DBG "the node is dirent node\n");
680 printk(JFFS2_DBG "pino:\t%#08x\n", je32_to_cpu(node.d.pino));
681 printk(JFFS2_DBG "version:\t%#08x\n", je32_to_cpu(node.d.version));
682 printk(JFFS2_DBG "ino:\t%#08x\n", je32_to_cpu(node.d.ino));
683 printk(JFFS2_DBG "mctime:\t%#08x\n", je32_to_cpu(node.d.mctime));
684 printk(JFFS2_DBG "nsize:\t%#02x\n", node.d.nsize);
685 printk(JFFS2_DBG "type:\t%#02x\n", node.d.type);
686 printk(JFFS2_DBG "node_crc:\t%#08x\n", je32_to_cpu(node.d.node_crc));
687 printk(JFFS2_DBG "name_crc:\t%#08x\n", je32_to_cpu(node.d.name_crc));
689 node.d.name[node.d.nsize] = '\0';
690 printk(JFFS2_DBG "name:\t\"%s\"\n", node.d.name);
692 crc = crc32(0, &node.d, sizeof(node.d) - 8);
693 if (crc != je32_to_cpu(node.d.node_crc)) {
694 JFFS2_ERROR("wrong node header CRC.\n");
695 return;
697 break;
699 default:
700 printk(JFFS2_DBG "node type is unknown\n");
701 break;
704 #endif /* JFFS2_DBG_DUMPS || JFFS2_DBG_PARANOIA_CHECKS */