[JFFS2] Debug code clean up - step 3
[linux-2.6.git] / fs / jffs2 / debug.c
1 /*
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  *
10  * $Id: debug.c,v 1.7 2005/07/24 15:14:14 dedekind Exp $
11  *
12  */
13 #include <linux/kernel.h>
14 #include <linux/pagemap.h>
15 #include <linux/crc32.h>
16 #include <linux/jffs2.h>
17 #include "nodelist.h"
18 #include "debug.h"
19
20 #ifdef JFFS2_DBG_PARANOIA_CHECKS
21 /*
22  * Check the fragtree.
23  */
24 void
25 __jffs2_dbg_fragtree_paranoia_check(struct jffs2_inode_info *f)
26 {
27         down(&f->sem);
28         __jffs2_dbg_fragtree_paranoia_check_nolock(f);
29         up(&f->sem);
30 }
31         
32 void
33 __jffs2_dbg_fragtree_paranoia_check_nolock(struct jffs2_inode_info *f)
34 {
35         struct jffs2_node_frag *frag;
36         int bitched = 0;
37
38         for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) {
39                 struct jffs2_full_dnode *fn = frag->node;
40
41                 if (!fn || !fn->raw)
42                         continue;
43
44                 if (ref_flags(fn->raw) == REF_PRISTINE) {
45                         if (fn->frags > 1) {
46                                 JFFS2_ERROR("REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2.\n",
47                                                 ref_offset(fn->raw), fn->frags);
48                                 bitched = 1;
49                         }
50
51                         /* A hole node which isn't multi-page should be garbage-collected
52                            and merged anyway, so we just check for the frag size here,
53                            rather than mucking around with actually reading the node
54                            and checking the compression type, which is the real way
55                            to tell a hole node. */
56                         if (frag->ofs & (PAGE_CACHE_SIZE-1) && frag_prev(frag)
57                                         && frag_prev(frag)->size < PAGE_CACHE_SIZE && frag_prev(frag)->node) {
58                                 JFFS2_ERROR("REF_PRISTINE node at 0x%08x had a previous non-hole frag "
59                                                 "in the same page. Tell dwmw2.\n", ref_offset(fn->raw));
60                                 bitched = 1;
61                         }
62
63                         if ((frag->ofs+frag->size) & (PAGE_CACHE_SIZE-1) && frag_next(frag)
64                                         && frag_next(frag)->size < PAGE_CACHE_SIZE && frag_next(frag)->node) {
65                                 JFFS2_ERROR("REF_PRISTINE node at 0x%08x (%08x-%08x) had a following "
66                                                 "non-hole frag in the same page. Tell dwmw2.\n",
67                                                ref_offset(fn->raw), frag->ofs, frag->ofs+frag->size);
68                                 bitched = 1;
69                         }
70                 }
71         }
72
73         if (bitched) {
74                 JFFS2_ERROR("fragtree is corrupted.\n");
75                 __jffs2_dbg_dump_fragtree_nolock(f);
76                 BUG();
77         }
78 }
79
80 /*
81  * Check if the flash contains all 0xFF before we start writing.
82  */
83 void
84 __jffs2_dbg_prewrite_paranoia_check(struct jffs2_sb_info *c,
85                                     uint32_t ofs, int len)
86 {
87         size_t retlen;
88         int ret, i;
89         unsigned char *buf;
90
91         buf = kmalloc(len, GFP_KERNEL);
92         if (!buf)
93                 return;
94
95         ret = jffs2_flash_read(c, ofs, len, &retlen, buf);
96         if (ret || (retlen != len)) {
97                 JFFS2_WARNING("read %d bytes failed or short. ret %d, retlen %zd.\n",
98                                 len, ret, retlen);
99                 kfree(buf);
100                 return;
101         }
102
103         ret = 0;
104         for (i = 0; i < len; i++)
105                 if (buf[i] != 0xff)
106                         ret = 1;
107
108         if (ret) {
109                 JFFS2_ERROR("argh, about to write node to %#08x on flash, but there are data "
110                         "already there. The first corrupted byte is at %#08x offset.\n", ofs, ofs + i);
111                 __jffs2_dbg_dump_buffer(buf, len, ofs);
112                 kfree(buf);
113                 BUG();
114         }
115
116         kfree(buf);
117 }
118
119 /*
120  * Check the space accounting and node_ref list correctness for the JFFS2 erasable block 'jeb'.
121  */
122 void
123 __jffs2_dbg_acct_paranoia_check(struct jffs2_sb_info *c,
124                                 struct jffs2_eraseblock *jeb)
125 {
126         spin_lock(&c->erase_completion_lock);
127         __jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
128         spin_unlock(&c->erase_completion_lock);
129 }
130         
131 void
132 __jffs2_dbg_acct_paranoia_check_nolock(struct jffs2_sb_info *c,
133                                        struct jffs2_eraseblock *jeb)
134 {
135         uint32_t my_used_size = 0;
136         uint32_t my_unchecked_size = 0;
137         uint32_t my_dirty_size = 0;
138         struct jffs2_raw_node_ref *ref2 = jeb->first_node;
139
140         while (ref2) {
141                 uint32_t totlen = ref_totlen(c, jeb, ref2);
142
143                 if (ref2->flash_offset < jeb->offset ||
144                                 ref2->flash_offset > jeb->offset + c->sector_size) {
145                         JFFS2_ERROR("node_ref %#08x shouldn't be in block at %#08x.\n",
146                                 ref_offset(ref2), jeb->offset);
147                         goto error;
148
149                 }
150                 if (ref_flags(ref2) == REF_UNCHECKED)
151                         my_unchecked_size += totlen;
152                 else if (!ref_obsolete(ref2))
153                         my_used_size += totlen;
154                 else
155                         my_dirty_size += totlen;
156
157                 if ((!ref2->next_phys) != (ref2 == jeb->last_node)) {
158                         JFFS2_ERROR("node_ref for node at %#08x (mem %p) has next_phys at %#08x (mem %p), "
159                                 "last_node is at %#08x (mem %p).\n",
160                                 ref_offset(ref2), ref2, ref_offset(ref2->next_phys), ref2->next_phys,
161                                 ref_offset(jeb->last_node), jeb->last_node);
162                         goto error;
163                 }
164                 ref2 = ref2->next_phys;
165         }
166
167         if (my_used_size != jeb->used_size) {
168                 JFFS2_ERROR("Calculated used size %#08x != stored used size %#08x.\n",
169                         my_used_size, jeb->used_size);
170                 goto error;
171         }
172
173         if (my_unchecked_size != jeb->unchecked_size) {
174                 JFFS2_ERROR("Calculated unchecked size %#08x != stored unchecked size %#08x.\n",
175                         my_unchecked_size, jeb->unchecked_size);
176                 goto error;
177         }
178
179 #if 0
180         /* This should work when we implement ref->__totlen elemination */
181         if (my_dirty_size != jeb->dirty_size + jeb->wasted_size) {
182                 JFFS2_ERROR("Calculated dirty+wasted size %#08x != stored dirty + wasted size %#08x\n",
183                         my_dirty_size, jeb->dirty_size + jeb->wasted_size);
184                 goto error;
185         }
186
187         if (jeb->free_size == 0
188                 && my_used_size + my_unchecked_size + my_dirty_size != c->sector_size) {
189                 JFFS2_ERROR("The sum of all nodes in block (%#x) != size of block (%#x)\n",
190                         my_used_size + my_unchecked_size + my_dirty_size,
191                         c->sector_size);
192                 goto error;
193         }
194 #endif
195
196         return;
197
198 error:
199         __jffs2_dbg_dump_node_refs_nolock(c, jeb);
200         __jffs2_dbg_dump_jeb_nolock(jeb);
201         __jffs2_dbg_dump_block_lists_nolock(c);
202         BUG();
203         
204 }
205 #endif /* JFFS2_DBG_PARANOIA_CHECKS */
206
207 #if defined(JFFS2_DBG_DUMPS) || defined(JFFS2_DBG_PARANOIA_CHECKS)
208 /*
209  * Dump the node_refs of the 'jeb' JFFS2 eraseblock.
210  */
211 void
212 __jffs2_dbg_dump_node_refs(struct jffs2_sb_info *c,
213                            struct jffs2_eraseblock *jeb)
214 {
215         spin_lock(&c->erase_completion_lock);
216         __jffs2_dbg_dump_node_refs_nolock(c, jeb);
217         spin_unlock(&c->erase_completion_lock);
218 }
219
220 void
221 __jffs2_dbg_dump_node_refs_nolock(struct jffs2_sb_info *c,
222                                   struct jffs2_eraseblock *jeb)
223 {
224         struct jffs2_raw_node_ref *ref;
225         int i = 0;
226
227         JFFS2_DEBUG("Dump node_refs of the eraseblock %#08x\n", jeb->offset);
228         if (!jeb->first_node) {
229                 JFFS2_DEBUG("no nodes in the eraseblock %#08x\n", jeb->offset);
230                 return;
231         }
232
233         printk(JFFS2_DBG_LVL);
234         for (ref = jeb->first_node; ; ref = ref->next_phys) {
235                 printk("%#08x(%#x)", ref_offset(ref), ref->__totlen);
236                 if (ref->next_phys)
237                         printk("->");
238                 else
239                         break;
240                 if (++i == 4) {
241                         i = 0;
242                         printk("\n" JFFS2_DBG_LVL);
243                 }
244         }
245         printk("\n");
246 }
247
248 /*
249  * Dump an eraseblock's space accounting.
250  */
251 void
252 __jffs2_dbg_dump_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
253 {
254         spin_lock(&c->erase_completion_lock);
255         __jffs2_dbg_dump_jeb_nolock(jeb);
256         spin_unlock(&c->erase_completion_lock);
257 }
258
259 void
260 __jffs2_dbg_dump_jeb_nolock(struct jffs2_eraseblock *jeb)
261 {
262         if (!jeb)
263                 return;
264
265         JFFS2_DEBUG("dump space accounting for the eraseblock at %#08x:\n",
266                         jeb->offset);
267
268         printk(JFFS2_DBG_LVL "used_size: %#08x\n",      jeb->used_size);
269         printk(JFFS2_DBG_LVL "dirty_size: %#08x\n",     jeb->dirty_size);
270         printk(JFFS2_DBG_LVL "wasted_size: %#08x\n",    jeb->wasted_size);
271         printk(JFFS2_DBG_LVL "unchecked_size: %#08x\n", jeb->unchecked_size);
272         printk(JFFS2_DBG_LVL "free_size: %#08x\n",      jeb->free_size);
273 }
274
275 void
276 __jffs2_dbg_dump_block_lists(struct jffs2_sb_info *c)
277 {
278         spin_lock(&c->erase_completion_lock);
279         __jffs2_dbg_dump_block_lists_nolock(c);
280         spin_unlock(&c->erase_completion_lock);
281 }
282
283 void
284 __jffs2_dbg_dump_block_lists_nolock(struct jffs2_sb_info *c)
285 {
286         JFFS2_DEBUG("dump JFFS2 blocks lists:\n");
287         
288         printk(JFFS2_DBG_LVL "flash_size: %#08x\n",     c->flash_size);
289         printk(JFFS2_DBG_LVL "used_size: %#08x\n",      c->used_size);
290         printk(JFFS2_DBG_LVL "dirty_size: %#08x\n",     c->dirty_size);
291         printk(JFFS2_DBG_LVL "wasted_size: %#08x\n",    c->wasted_size);
292         printk(JFFS2_DBG_LVL "unchecked_size: %#08x\n", c->unchecked_size);
293         printk(JFFS2_DBG_LVL "free_size: %#08x\n",      c->free_size);
294         printk(JFFS2_DBG_LVL "erasing_size: %#08x\n",   c->erasing_size);
295         printk(JFFS2_DBG_LVL "bad_size: %#08x\n",       c->bad_size);
296         printk(JFFS2_DBG_LVL "sector_size: %#08x\n",    c->sector_size);
297         printk(JFFS2_DBG_LVL "jffs2_reserved_blocks size: %#08x\n",
298                                 c->sector_size * c->resv_blocks_write);
299
300         if (c->nextblock)
301                 printk(JFFS2_DBG_LVL "nextblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, "
302                         "unchecked %#08x, free %#08x)\n",
303                         c->nextblock->offset, c->nextblock->used_size,
304                         c->nextblock->dirty_size, c->nextblock->wasted_size,
305                         c->nextblock->unchecked_size, c->nextblock->free_size);
306         else
307                 printk(JFFS2_DBG_LVL "nextblock: NULL\n");
308
309         if (c->gcblock)
310                 printk(JFFS2_DBG_LVL "gcblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, "
311                         "unchecked %#08x, free %#08x)\n",
312                         c->gcblock->offset, c->gcblock->used_size, c->gcblock->dirty_size,
313                         c->gcblock->wasted_size, c->gcblock->unchecked_size, c->gcblock->free_size);
314         else
315                 printk(JFFS2_DBG_LVL "gcblock: NULL\n");
316
317         if (list_empty(&c->clean_list)) {
318                 printk(JFFS2_DBG_LVL "clean_list: empty\n");
319         } else {
320                 struct list_head *this;
321                 int numblocks = 0;
322                 uint32_t dirty = 0;
323
324                 list_for_each(this, &c->clean_list) {
325                         struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
326                         numblocks ++;
327                         dirty += jeb->wasted_size;
328                         if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
329                                 printk(JFFS2_DBG_LVL "clean_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, "
330                                         "unchecked %#08x, free %#08x)\n",
331                                         jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
332                                         jeb->unchecked_size, jeb->free_size);
333                         }
334                 }
335
336                 printk (JFFS2_DBG_LVL "Contains %d blocks with total wasted size %u, average wasted size: %u\n",
337                         numblocks, dirty, dirty / numblocks);
338         }
339
340         if (list_empty(&c->very_dirty_list)) {
341                 printk(JFFS2_DBG_LVL "very_dirty_list: empty\n");
342         } else {
343                 struct list_head *this;
344                 int numblocks = 0;
345                 uint32_t dirty = 0;
346
347                 list_for_each(this, &c->very_dirty_list) {
348                         struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
349
350                         numblocks ++;
351                         dirty += jeb->dirty_size;
352                         if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
353                                 printk(JFFS2_DBG_LVL "very_dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, "
354                                         "unchecked %#08x, free %#08x)\n",
355                                         jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
356                                         jeb->unchecked_size, jeb->free_size);
357                         }
358                 }
359
360                 printk (JFFS2_DBG_LVL "Contains %d blocks with total dirty size %u, average dirty size: %u\n",
361                         numblocks, dirty, dirty / numblocks);
362         }
363
364         if (list_empty(&c->dirty_list)) {
365                 printk(JFFS2_DBG_LVL "dirty_list: empty\n");
366         } else {
367                 struct list_head *this;
368                 int numblocks = 0;
369                 uint32_t dirty = 0;
370
371                 list_for_each(this, &c->dirty_list) {
372                         struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
373
374                         numblocks ++;
375                         dirty += jeb->dirty_size;
376                         if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
377                                 printk(JFFS2_DBG_LVL "dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, "
378                                         "unchecked %#08x, free %#08x)\n",
379                                         jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
380                                         jeb->unchecked_size, jeb->free_size);
381                         }
382                 }
383
384                 printk (JFFS2_DBG_LVL "contains %d blocks with total dirty size %u, average dirty size: %u\n",
385                         numblocks, dirty, dirty / numblocks);
386         }
387
388         if (list_empty(&c->erasable_list)) {
389                 printk(JFFS2_DBG_LVL "erasable_list: empty\n");
390         } else {
391                 struct list_head *this;
392
393                 list_for_each(this, &c->erasable_list) {
394                         struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
395
396                         if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
397                                 printk(JFFS2_DBG_LVL "erasable_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, "
398                                         "unchecked %#08x, free %#08x)\n",
399                                         jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
400                                         jeb->unchecked_size, jeb->free_size);
401                         }
402                 }
403         }
404
405         if (list_empty(&c->erasing_list)) {
406                 printk(JFFS2_DBG_LVL "erasing_list: empty\n");
407         } else {
408                 struct list_head *this;
409
410                 list_for_each(this, &c->erasing_list) {
411                         struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
412
413                         if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
414                                 printk(JFFS2_DBG_LVL "erasing_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, "
415                                         "unchecked %#08x, free %#08x)\n",
416                                         jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
417                                         jeb->unchecked_size, jeb->free_size);
418                         }
419                 }
420         }
421
422         if (list_empty(&c->erase_pending_list)) {
423                 printk(JFFS2_DBG_LVL "erase_pending_list: empty\n");
424         } else {
425                 struct list_head *this;
426
427                 list_for_each(this, &c->erase_pending_list) {
428                         struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
429
430                         if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
431                                 printk(JFFS2_DBG_LVL "erase_pending_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, "
432                                         "unchecked %#08x, free %#08x)\n",
433                                         jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
434                                         jeb->unchecked_size, jeb->free_size);
435                         }
436                 }
437         }
438
439         if (list_empty(&c->erasable_pending_wbuf_list)) {
440                 printk(JFFS2_DBG_LVL "erasable_pending_wbuf_list: empty\n");
441         } else {
442                 struct list_head *this;
443
444                 list_for_each(this, &c->erasable_pending_wbuf_list) {
445                         struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
446
447                         if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
448                                 printk(JFFS2_DBG_LVL "erasable_pending_wbuf_list: %#08x (used %#08x, dirty %#08x, "
449                                         "wasted %#08x, unchecked %#08x, free %#08x)\n",
450                                         jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
451                                         jeb->unchecked_size, jeb->free_size);
452                         }
453                 }
454         }
455
456         if (list_empty(&c->free_list)) {
457                 printk(JFFS2_DBG_LVL "free_list: empty\n");
458         } else {
459                 struct list_head *this;
460
461                 list_for_each(this, &c->free_list) {
462                         struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
463
464                         if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
465                                 printk(JFFS2_DBG_LVL "free_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, "
466                                         "unchecked %#08x, free %#08x)\n",
467                                         jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
468                                         jeb->unchecked_size, jeb->free_size);
469                         }
470                 }
471         }
472
473         if (list_empty(&c->bad_list)) {
474                 printk(JFFS2_DBG_LVL "bad_list: empty\n");
475         } else {
476                 struct list_head *this;
477
478                 list_for_each(this, &c->bad_list) {
479                         struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
480
481                         if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
482                                 printk(JFFS2_DBG_LVL "bad_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, "
483                                         "unchecked %#08x, free %#08x)\n",
484                                         jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
485                                         jeb->unchecked_size, jeb->free_size);
486                         }
487                 }
488         }
489
490         if (list_empty(&c->bad_used_list)) {
491                 printk(JFFS2_DBG_LVL "bad_used_list: empty\n");
492         } else {
493                 struct list_head *this;
494
495                 list_for_each(this, &c->bad_used_list) {
496                         struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
497
498                         if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
499                                 printk(JFFS2_DBG_LVL "bad_used_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, "
500                                         "unchecked %#08x, free %#08x)\n",
501                                         jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
502                                         jeb->unchecked_size, jeb->free_size);
503                         }
504                 }
505         }
506 }
507
508 void
509 __jffs2_dbg_dump_fragtree(struct jffs2_inode_info *f)
510 {
511         down(&f->sem);
512         jffs2_dbg_dump_fragtree_nolock(f);
513         up(&f->sem);
514 }
515
516 void
517 __jffs2_dbg_dump_fragtree_nolock(struct jffs2_inode_info *f)
518 {
519         struct jffs2_node_frag *this = frag_first(&f->fragtree);
520         uint32_t lastofs = 0;
521         int buggy = 0;
522
523         JFFS2_DEBUG("dump fragtree of ino #%u\n", f->inocache->ino);
524         while(this) {
525                 if (this->node)
526                         printk(JFFS2_DBG_LVL "frag %#04x-%#04x: %#08x(%d) on flash (*%p), left (%p), "
527                                 "right (%p), parent (%p)\n",
528                                 this->ofs, this->ofs+this->size, ref_offset(this->node->raw),
529                                 ref_flags(this->node->raw), this, frag_left(this), frag_right(this),
530                                 frag_parent(this));
531                 else
532                         printk(JFFS2_DBG_LVL "frag %#04x-%#04x: hole (*%p). left (%p), right (%p), parent (%p)\n",
533                                 this->ofs, this->ofs+this->size, this, frag_left(this),
534                                 frag_right(this), frag_parent(this));
535                 if (this->ofs != lastofs)
536                         buggy = 1;
537                 lastofs = this->ofs + this->size;
538                 this = frag_next(this);
539         }
540
541         if (f->metadata)
542                 printk(JFFS2_DBG_LVL "metadata at 0x%08x\n", ref_offset(f->metadata->raw));
543
544         if (buggy) {
545                 JFFS2_ERROR("frag tree got a hole in it.\n");
546                 BUG();
547         }
548 }
549
550 #define JFFS2_BUFDUMP_BYTES_PER_LINE    32
551 void
552 __jffs2_dbg_dump_buffer(unsigned char *buf, int len, uint32_t offs)
553 {
554         int skip;
555         int i;
556         
557         JFFS2_DEBUG("dump from offset %#08x to offset %#08x (%x bytes).\n",
558                 offs, offs + len, len);
559         i = skip = offs % JFFS2_BUFDUMP_BYTES_PER_LINE;
560         offs = offs & ~(JFFS2_BUFDUMP_BYTES_PER_LINE - 1);
561         
562         if (skip != 0)
563                 printk(JFFS2_DBG_LVL "%#08x: ", offs);
564         
565         while (skip--)
566                 printk("   ");
567
568         while (i < len) {
569                 if ((i % JFFS2_BUFDUMP_BYTES_PER_LINE) == 0 && i != len -1) {
570                         if (i != 0)
571                                 printk("\n");
572                         offs += JFFS2_BUFDUMP_BYTES_PER_LINE;
573                         printk(JFFS2_DBG_LVL "%0#8x: ", offs);
574                 }
575
576                 printk("%02x ", buf[i]);
577                 
578                 i += 1;
579         }
580
581         printk("\n");
582 }
583
584 /*
585  * Dump a JFFS2 node.
586  */
587 void
588 __jffs2_dbg_dump_node(struct jffs2_sb_info *c, uint32_t ofs)
589 {
590         union jffs2_node_union node;
591         int len = sizeof(union jffs2_node_union);
592         size_t retlen;
593         uint32_t crc;
594         int ret;
595         
596         JFFS2_DEBUG("dump node at offset %#08x.\n", ofs);
597
598         ret = jffs2_flash_read(c, ofs, len, &retlen, (unsigned char *)&node);
599         if (ret || (retlen != len)) {
600                 JFFS2_ERROR("read %d bytes failed or short. ret %d, retlen %zd.\n",
601                         len, ret, retlen);
602                 return;
603         }
604
605         printk(JFFS2_DBG_LVL "magic:\t%#04x\n",
606                 je16_to_cpu(node.u.magic));
607         printk(JFFS2_DBG_LVL "nodetype:\t%#04x\n",
608                 je16_to_cpu(node.u.nodetype));
609         printk(JFFS2_DBG_LVL "totlen:\t%#08x\n",
610                 je32_to_cpu(node.u.totlen));
611         printk(JFFS2_DBG_LVL "hdr_crc:\t%#08x\n",
612                 je32_to_cpu(node.u.hdr_crc));
613         
614         crc = crc32(0, &node.u, sizeof(node.u) - 4);
615         if (crc != je32_to_cpu(node.u.hdr_crc)) {
616                 JFFS2_ERROR("wrong common header CRC.\n");
617                 return;
618         }
619         
620         if (je16_to_cpu(node.u.magic) != JFFS2_MAGIC_BITMASK &&
621                 je16_to_cpu(node.u.magic) != JFFS2_OLD_MAGIC_BITMASK)
622         {
623                 JFFS2_ERROR("wrong node magic: %#04x instead of %#04x.\n",
624                         je16_to_cpu(node.u.magic), JFFS2_MAGIC_BITMASK);
625                 return;
626         }
627
628         switch(je16_to_cpu(node.u.nodetype)) {
629
630         case JFFS2_NODETYPE_INODE:
631
632                 printk(JFFS2_DBG_LVL "the node is inode node\n");
633                 printk(JFFS2_DBG_LVL "ino:\t%#08x\n",
634                                 je32_to_cpu(node.i.ino));
635                 printk(JFFS2_DBG_LVL "version:\t%#08x\n",
636                                 je32_to_cpu(node.i.version));
637                 printk(JFFS2_DBG_LVL "mode:\t%#08x\n",
638                                 node.i.mode.m);
639                 printk(JFFS2_DBG_LVL "uid:\t%#04x\n",
640                                 je16_to_cpu(node.i.uid));
641                 printk(JFFS2_DBG_LVL "gid:\t%#04x\n",
642                                 je16_to_cpu(node.i.gid));
643                 printk(JFFS2_DBG_LVL "isize:\t%#08x\n",
644                                 je32_to_cpu(node.i.isize));
645                 printk(JFFS2_DBG_LVL "atime:\t%#08x\n",
646                                 je32_to_cpu(node.i.atime));
647                 printk(JFFS2_DBG_LVL "mtime:\t%#08x\n",
648                                 je32_to_cpu(node.i.mtime));
649                 printk(JFFS2_DBG_LVL "ctime:\t%#08x\n",
650                                 je32_to_cpu(node.i.ctime));
651                 printk(JFFS2_DBG_LVL "offset:\t%#08x\n",
652                                 je32_to_cpu(node.i.offset));
653                 printk(JFFS2_DBG_LVL "csize:\t%#08x\n",
654                                 je32_to_cpu(node.i.csize));
655                 printk(JFFS2_DBG_LVL "dsize:\t%#08x\n",
656                                 je32_to_cpu(node.i.dsize));
657                 printk(JFFS2_DBG_LVL "compr:\t%#02x\n",
658                                 node.i.compr);
659                 printk(JFFS2_DBG_LVL "usercompr:\t%#02x\n",
660                                 node.i.usercompr);
661                 printk(JFFS2_DBG_LVL "flags:\t%#04x\n",
662                                 je16_to_cpu(node.i.flags));
663                 printk(JFFS2_DBG_LVL "data_crc:\t%#08x\n",
664                                 je32_to_cpu(node.i.data_crc));
665                 printk(JFFS2_DBG_LVL "node_crc:\t%#08x\n",
666                                 je32_to_cpu(node.i.node_crc));
667                 crc = crc32(0, &node.i, sizeof(node.i) - 8); 
668                 if (crc != je32_to_cpu(node.i.node_crc)) {
669                         JFFS2_ERROR("wrong node header CRC.\n");
670                         return;
671                 }
672                 break;
673
674         case JFFS2_NODETYPE_DIRENT:
675
676                 printk(JFFS2_DBG_LVL "the node is dirent node\n");
677                 printk(JFFS2_DBG_LVL "pino:\t%#08x\n",
678                                 je32_to_cpu(node.d.pino));
679                 printk(JFFS2_DBG_LVL "version:\t%#08x\n",
680                                 je32_to_cpu(node.d.version));
681                 printk(JFFS2_DBG_LVL "ino:\t%#08x\n",
682                                 je32_to_cpu(node.d.ino));
683                 printk(JFFS2_DBG_LVL "mctime:\t%#08x\n",
684                                 je32_to_cpu(node.d.mctime));
685                 printk(JFFS2_DBG_LVL "nsize:\t%#02x\n",
686                                 node.d.nsize);
687                 printk(JFFS2_DBG_LVL "type:\t%#02x\n",
688                                 node.d.type);
689                 printk(JFFS2_DBG_LVL "node_crc:\t%#08x\n",
690                                 je32_to_cpu(node.d.node_crc));
691                 printk(JFFS2_DBG_LVL "name_crc:\t%#08x\n",
692                                 je32_to_cpu(node.d.name_crc));
693                 
694                 node.d.name[node.d.nsize] = '\0';
695                 printk(JFFS2_DBG_LVL "name:\t\"%s\"\n", node.d.name);
696
697                 crc = crc32(0, &node.d, sizeof(node.d) - 8); 
698                 if (crc != je32_to_cpu(node.d.node_crc)) {
699                         JFFS2_ERROR("wrong node header CRC.\n");
700                         return;
701                 }
702                 break;
703
704         default:
705                 printk(JFFS2_DBG_LVL "node type is unknown\n");
706                 break;
707         }
708 }
709 #endif /* JFFS2_DBG_DUMPS || JFFS2_DBG_PARANOIA_CHECKS */