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