sync hh.org
[hh.org.git] / fs / jffs2 / debug.c
blob72b4fc13a106053bfa64773f3d9e9609ce5ebd7d
1 /*
2 * JFFS2 -- Journalling Flash File System, Version 2.
4 * Copyright (C) 2001-2003 Red Hat, Inc.
6 * Created by David Woodhouse <dwmw2@infradead.org>
8 * For licensing information, see the file 'LICENCE' in this directory.
10 * $Id: debug.c,v 1.12 2005/11/07 11:14:39 gleixner Exp $
13 #include <linux/kernel.h>
14 #include <linux/types.h>
15 #include <linux/pagemap.h>
16 #include <linux/crc32.h>
17 #include <linux/jffs2.h>
18 #include <linux/mtd/mtd.h>
19 #include "nodelist.h"
20 #include "debug.h"
22 #ifdef JFFS2_DBG_SANITY_CHECKS
24 void
25 __jffs2_dbg_acct_sanity_check_nolock(struct jffs2_sb_info *c,
26 struct jffs2_eraseblock *jeb)
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);
32 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,
34 jeb->wasted_size, jeb->unchecked_size, c->sector_size);
35 BUG();
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");
41 JFFS2_ERROR("free %#08x + dirty %#08x + used %#08x + erasing %#08x + bad %#08x + wasted %#08x + unchecked %#08x != total %#08x.\n",
42 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();
48 void
49 __jffs2_dbg_acct_sanity_check(struct jffs2_sb_info *c,
50 struct jffs2_eraseblock *jeb)
52 spin_lock(&c->erase_completion_lock);
53 jffs2_dbg_acct_sanity_check_nolock(c, jeb);
54 spin_unlock(&c->erase_completion_lock);
57 #endif /* JFFS2_DBG_SANITY_CHECKS */
59 #ifdef JFFS2_DBG_PARANOIA_CHECKS
61 * Check the fragtree.
63 void
64 __jffs2_dbg_fragtree_paranoia_check(struct jffs2_inode_info *f)
66 down(&f->sem);
67 __jffs2_dbg_fragtree_paranoia_check_nolock(f);
68 up(&f->sem);
71 void
72 __jffs2_dbg_fragtree_paranoia_check_nolock(struct jffs2_inode_info *f)
74 struct jffs2_node_frag *frag;
75 int bitched = 0;
77 for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) {
78 struct jffs2_full_dnode *fn = frag->node;
80 if (!fn || !fn->raw)
81 continue;
83 if (ref_flags(fn->raw) == REF_PRISTINE) {
84 if (fn->frags > 1) {
85 JFFS2_ERROR("REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2.\n",
86 ref_offset(fn->raw), fn->frags);
87 bitched = 1;
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) {
97 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));
99 bitched = 1;
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) {
104 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);
106 bitched = 1;
111 if (bitched) {
112 JFFS2_ERROR("fragtree is corrupted.\n");
113 __jffs2_dbg_dump_fragtree_nolock(f);
114 BUG();
119 * Check if the flash contains all 0xFF before we start writing.
121 void
122 __jffs2_dbg_prewrite_paranoia_check(struct jffs2_sb_info *c,
123 uint32_t ofs, int len)
125 size_t retlen;
126 int ret, i;
127 unsigned char *buf;
129 buf = kmalloc(len, GFP_KERNEL);
130 if (!buf)
131 return;
133 ret = jffs2_flash_read(c, ofs, len, &retlen, buf);
134 if (ret || (retlen != len)) {
135 JFFS2_WARNING("read %d bytes failed or short. ret %d, retlen %zd.\n",
136 len, ret, retlen);
137 kfree(buf);
138 return;
141 ret = 0;
142 for (i = 0; i < len; i++)
143 if (buf[i] != 0xff)
144 ret = 1;
146 if (ret) {
147 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);
149 __jffs2_dbg_dump_buffer(buf, len, ofs);
150 kfree(buf);
151 BUG();
154 kfree(buf);
158 * Check the space accounting and node_ref list correctness for the JFFS2 erasable block 'jeb'.
160 void
161 __jffs2_dbg_acct_paranoia_check(struct jffs2_sb_info *c,
162 struct jffs2_eraseblock *jeb)
164 spin_lock(&c->erase_completion_lock);
165 __jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
166 spin_unlock(&c->erase_completion_lock);
169 void
170 __jffs2_dbg_acct_paranoia_check_nolock(struct jffs2_sb_info *c,
171 struct jffs2_eraseblock *jeb)
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;
178 while (ref2) {
179 uint32_t totlen = ref_totlen(c, jeb, ref2);
181 if (ref2->flash_offset < jeb->offset ||
182 ref2->flash_offset > jeb->offset + c->sector_size) {
183 JFFS2_ERROR("node_ref %#08x shouldn't be in block at %#08x.\n",
184 ref_offset(ref2), jeb->offset);
185 goto error;
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;
195 if ((!ref_next(ref2)) != (ref2 == jeb->last_node)) {
196 JFFS2_ERROR("node_ref for node at %#08x (mem %p) has next at %#08x (mem %p), last_node is at %#08x (mem %p).\n",
197 ref_offset(ref2), ref2, ref_offset(ref_next(ref2)), ref_next(ref2),
198 ref_offset(jeb->last_node), jeb->last_node);
199 goto error;
201 ref2 = ref_next(ref2);
204 if (my_used_size != jeb->used_size) {
205 JFFS2_ERROR("Calculated used size %#08x != stored used size %#08x.\n",
206 my_used_size, jeb->used_size);
207 goto error;
210 if (my_unchecked_size != jeb->unchecked_size) {
211 JFFS2_ERROR("Calculated unchecked size %#08x != stored unchecked size %#08x.\n",
212 my_unchecked_size, jeb->unchecked_size);
213 goto error;
216 #if 0
217 /* This should work when we implement ref->__totlen elemination */
218 if (my_dirty_size != jeb->dirty_size + jeb->wasted_size) {
219 JFFS2_ERROR("Calculated dirty+wasted size %#08x != stored dirty + wasted size %#08x\n",
220 my_dirty_size, jeb->dirty_size + jeb->wasted_size);
221 goto error;
224 if (jeb->free_size == 0
225 && my_used_size + my_unchecked_size + my_dirty_size != c->sector_size) {
226 JFFS2_ERROR("The sum of all nodes in block (%#x) != size of block (%#x)\n",
227 my_used_size + my_unchecked_size + my_dirty_size,
228 c->sector_size);
229 goto error;
231 #endif
233 return;
235 error:
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();
242 #endif /* JFFS2_DBG_PARANOIA_CHECKS */
244 #if defined(JFFS2_DBG_DUMPS) || defined(JFFS2_DBG_PARANOIA_CHECKS)
246 * Dump the node_refs of the 'jeb' JFFS2 eraseblock.
248 void
249 __jffs2_dbg_dump_node_refs(struct jffs2_sb_info *c,
250 struct jffs2_eraseblock *jeb)
252 spin_lock(&c->erase_completion_lock);
253 __jffs2_dbg_dump_node_refs_nolock(c, jeb);
254 spin_unlock(&c->erase_completion_lock);
257 void
258 __jffs2_dbg_dump_node_refs_nolock(struct jffs2_sb_info *c,
259 struct jffs2_eraseblock *jeb)
261 struct jffs2_raw_node_ref *ref;
262 int i = 0;
264 printk(JFFS2_DBG_MSG_PREFIX " Dump node_refs of the eraseblock %#08x\n", jeb->offset);
265 if (!jeb->first_node) {
266 printk(JFFS2_DBG_MSG_PREFIX " no nodes in the eraseblock %#08x\n", jeb->offset);
267 return;
270 printk(JFFS2_DBG);
271 for (ref = jeb->first_node; ; ref = ref_next(ref)) {
272 printk("%#08x(%#x)", ref_offset(ref), ref->__totlen);
273 if (ref_next(ref))
274 printk("->");
275 else
276 break;
277 if (++i == 4) {
278 i = 0;
279 printk("\n" JFFS2_DBG);
282 printk("\n");
286 * Dump an eraseblock's space accounting.
288 void
289 __jffs2_dbg_dump_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
291 spin_lock(&c->erase_completion_lock);
292 __jffs2_dbg_dump_jeb_nolock(jeb);
293 spin_unlock(&c->erase_completion_lock);
296 void
297 __jffs2_dbg_dump_jeb_nolock(struct jffs2_eraseblock *jeb)
299 if (!jeb)
300 return;
302 printk(JFFS2_DBG_MSG_PREFIX " dump space accounting for the eraseblock at %#08x:\n",
303 jeb->offset);
305 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);
312 void
313 __jffs2_dbg_dump_block_lists(struct jffs2_sb_info *c)
315 spin_lock(&c->erase_completion_lock);
316 __jffs2_dbg_dump_block_lists_nolock(c);
317 spin_unlock(&c->erase_completion_lock);
320 void
321 __jffs2_dbg_dump_block_lists_nolock(struct jffs2_sb_info *c)
323 printk(JFFS2_DBG_MSG_PREFIX " dump JFFS2 blocks lists:\n");
325 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",
335 c->sector_size * c->resv_blocks_write);
337 if (c->nextblock)
338 printk(JFFS2_DBG "nextblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
339 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);
342 else
343 printk(JFFS2_DBG "nextblock: NULL\n");
345 if (c->gcblock)
346 printk(JFFS2_DBG "gcblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
347 c->gcblock->offset, c->gcblock->used_size, c->gcblock->dirty_size,
348 c->gcblock->wasted_size, c->gcblock->unchecked_size, c->gcblock->free_size);
349 else
350 printk(JFFS2_DBG "gcblock: NULL\n");
352 if (list_empty(&c->clean_list)) {
353 printk(JFFS2_DBG "clean_list: empty\n");
354 } else {
355 struct list_head *this;
356 int numblocks = 0;
357 uint32_t dirty = 0;
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)) {
364 printk(JFFS2_DBG "clean_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
365 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
366 jeb->unchecked_size, jeb->free_size);
370 printk (JFFS2_DBG "Contains %d blocks with total wasted size %u, average wasted size: %u\n",
371 numblocks, dirty, dirty / numblocks);
374 if (list_empty(&c->very_dirty_list)) {
375 printk(JFFS2_DBG "very_dirty_list: empty\n");
376 } else {
377 struct list_head *this;
378 int numblocks = 0;
379 uint32_t dirty = 0;
381 list_for_each(this, &c->very_dirty_list) {
382 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
384 numblocks ++;
385 dirty += jeb->dirty_size;
386 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
387 printk(JFFS2_DBG "very_dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
388 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
389 jeb->unchecked_size, jeb->free_size);
393 printk (JFFS2_DBG "Contains %d blocks with total dirty size %u, average dirty size: %u\n",
394 numblocks, dirty, dirty / numblocks);
397 if (list_empty(&c->dirty_list)) {
398 printk(JFFS2_DBG "dirty_list: empty\n");
399 } else {
400 struct list_head *this;
401 int numblocks = 0;
402 uint32_t dirty = 0;
404 list_for_each(this, &c->dirty_list) {
405 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
407 numblocks ++;
408 dirty += jeb->dirty_size;
409 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
410 printk(JFFS2_DBG "dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
411 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
412 jeb->unchecked_size, jeb->free_size);
416 printk (JFFS2_DBG "contains %d blocks with total dirty size %u, average dirty size: %u\n",
417 numblocks, dirty, dirty / numblocks);
420 if (list_empty(&c->erasable_list)) {
421 printk(JFFS2_DBG "erasable_list: empty\n");
422 } else {
423 struct list_head *this;
425 list_for_each(this, &c->erasable_list) {
426 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
428 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
429 printk(JFFS2_DBG "erasable_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
430 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
431 jeb->unchecked_size, jeb->free_size);
436 if (list_empty(&c->erasing_list)) {
437 printk(JFFS2_DBG "erasing_list: empty\n");
438 } else {
439 struct list_head *this;
441 list_for_each(this, &c->erasing_list) {
442 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
444 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
445 printk(JFFS2_DBG "erasing_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
446 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
447 jeb->unchecked_size, jeb->free_size);
452 if (list_empty(&c->erase_pending_list)) {
453 printk(JFFS2_DBG "erase_pending_list: empty\n");
454 } else {
455 struct list_head *this;
457 list_for_each(this, &c->erase_pending_list) {
458 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
460 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
461 printk(JFFS2_DBG "erase_pending_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
462 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
463 jeb->unchecked_size, jeb->free_size);
468 if (list_empty(&c->erasable_pending_wbuf_list)) {
469 printk(JFFS2_DBG "erasable_pending_wbuf_list: empty\n");
470 } else {
471 struct list_head *this;
473 list_for_each(this, &c->erasable_pending_wbuf_list) {
474 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
476 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
477 printk(JFFS2_DBG "erasable_pending_wbuf_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
478 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
479 jeb->unchecked_size, jeb->free_size);
484 if (list_empty(&c->free_list)) {
485 printk(JFFS2_DBG "free_list: empty\n");
486 } else {
487 struct list_head *this;
489 list_for_each(this, &c->free_list) {
490 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
492 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
493 printk(JFFS2_DBG "free_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
494 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
495 jeb->unchecked_size, jeb->free_size);
500 if (list_empty(&c->bad_list)) {
501 printk(JFFS2_DBG "bad_list: empty\n");
502 } else {
503 struct list_head *this;
505 list_for_each(this, &c->bad_list) {
506 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
508 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
509 printk(JFFS2_DBG "bad_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
510 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
511 jeb->unchecked_size, jeb->free_size);
516 if (list_empty(&c->bad_used_list)) {
517 printk(JFFS2_DBG "bad_used_list: empty\n");
518 } else {
519 struct list_head *this;
521 list_for_each(this, &c->bad_used_list) {
522 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
524 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
525 printk(JFFS2_DBG "bad_used_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
526 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
527 jeb->unchecked_size, jeb->free_size);
533 void
534 __jffs2_dbg_dump_fragtree(struct jffs2_inode_info *f)
536 down(&f->sem);
537 jffs2_dbg_dump_fragtree_nolock(f);
538 up(&f->sem);
541 void
542 __jffs2_dbg_dump_fragtree_nolock(struct jffs2_inode_info *f)
544 struct jffs2_node_frag *this = frag_first(&f->fragtree);
545 uint32_t lastofs = 0;
546 int buggy = 0;
548 printk(JFFS2_DBG_MSG_PREFIX " dump fragtree of ino #%u\n", f->inocache->ino);
549 while(this) {
550 if (this->node)
551 printk(JFFS2_DBG "frag %#04x-%#04x: %#08x(%d) on flash (*%p), left (%p), right (%p), parent (%p)\n",
552 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));
555 else
556 printk(JFFS2_DBG "frag %#04x-%#04x: hole (*%p). left (%p), right (%p), parent (%p)\n",
557 this->ofs, this->ofs+this->size, this, frag_left(this),
558 frag_right(this), frag_parent(this));
559 if (this->ofs != lastofs)
560 buggy = 1;
561 lastofs = this->ofs + this->size;
562 this = frag_next(this);
565 if (f->metadata)
566 printk(JFFS2_DBG "metadata at 0x%08x\n", ref_offset(f->metadata->raw));
568 if (buggy) {
569 JFFS2_ERROR("frag tree got a hole in it.\n");
570 BUG();
574 #define JFFS2_BUFDUMP_BYTES_PER_LINE 32
575 void
576 __jffs2_dbg_dump_buffer(unsigned char *buf, int len, uint32_t offs)
578 int skip;
579 int i;
581 printk(JFFS2_DBG_MSG_PREFIX " dump from offset %#08x to offset %#08x (%x bytes).\n",
582 offs, offs + len, len);
583 i = skip = offs % JFFS2_BUFDUMP_BYTES_PER_LINE;
584 offs = offs & ~(JFFS2_BUFDUMP_BYTES_PER_LINE - 1);
586 if (skip != 0)
587 printk(JFFS2_DBG "%#08x: ", offs);
589 while (skip--)
590 printk(" ");
592 while (i < len) {
593 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;
597 printk(JFFS2_DBG "%0#8x: ", offs);
600 printk("%02x ", buf[i]);
602 i += 1;
605 printk("\n");
609 * Dump a JFFS2 node.
611 void
612 __jffs2_dbg_dump_node(struct jffs2_sb_info *c, uint32_t ofs)
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;
620 printk(JFFS2_DBG_MSG_PREFIX " dump node at offset %#08x.\n", ofs);
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;
629 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));
634 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;
640 if (je16_to_cpu(node.u.magic) != JFFS2_MAGIC_BITMASK &&
641 je16_to_cpu(node.u.magic) != JFFS2_OLD_MAGIC_BITMASK)
643 JFFS2_ERROR("wrong node magic: %#04x instead of %#04x.\n",
644 je16_to_cpu(node.u.magic), JFFS2_MAGIC_BITMASK);
645 return;
648 switch(je16_to_cpu(node.u.nodetype)) {
650 case JFFS2_NODETYPE_INODE:
652 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));
671 crc = crc32(0, &node.i, sizeof(node.i) - 8);
672 if (crc != je32_to_cpu(node.i.node_crc)) {
673 JFFS2_ERROR("wrong node header CRC.\n");
674 return;
676 break;
678 case JFFS2_NODETYPE_DIRENT:
680 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));
690 node.d.name[node.d.nsize] = '\0';
691 printk(JFFS2_DBG "name:\t\"%s\"\n", node.d.name);
693 crc = crc32(0, &node.d, sizeof(node.d) - 8);
694 if (crc != je32_to_cpu(node.d.node_crc)) {
695 JFFS2_ERROR("wrong node header CRC.\n");
696 return;
698 break;
700 default:
701 printk(JFFS2_DBG "node type is unknown\n");
702 break;
705 #endif /* JFFS2_DBG_DUMPS || JFFS2_DBG_PARANOIA_CHECKS */