]> nv-tegra.nvidia Code Review - linux-2.6.git/blob - fs/jffs2/debug.c
[JFFS2] Tidy up licensing/copyright boilerplate.
[linux-2.6.git] / fs / jffs2 / debug.c
1 /*
2  * JFFS2 -- Journalling Flash File System, Version 2.
3  *
4  * Copyright © 2001-2007 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  */
11
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"
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 %#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();
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 + 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();
44         }
45 }
46
47 void
48 __jffs2_dbg_acct_sanity_check(struct jffs2_sb_info *c,
49                               struct jffs2_eraseblock *jeb)
50 {
51         spin_lock(&c->erase_completion_lock);
52         jffs2_dbg_acct_sanity_check_nolock(c, jeb);
53         spin_unlock(&c->erase_completion_lock);
54 }
55
56 #endif /* JFFS2_DBG_SANITY_CHECKS */
57
58 #ifdef JFFS2_DBG_PARANOIA_CHECKS
59 /*
60  * Check the fragtree.
61  */
62 void
63 __jffs2_dbg_fragtree_paranoia_check(struct jffs2_inode_info *f)
64 {
65         down(&f->sem);
66         __jffs2_dbg_fragtree_paranoia_check_nolock(f);
67         up(&f->sem);
68 }
69
70 void
71 __jffs2_dbg_fragtree_paranoia_check_nolock(struct jffs2_inode_info *f)
72 {
73         struct jffs2_node_frag *frag;
74         int bitched = 0;
75
76         for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) {
77                 struct jffs2_full_dnode *fn = frag->node;
78
79                 if (!fn || !fn->raw)
80                         continue;
81
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;
87                         }
88
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;
99                         }
100
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;
106                         }
107                 }
108         }
109
110         if (bitched) {
111                 JFFS2_ERROR("fragtree is corrupted.\n");
112                 __jffs2_dbg_dump_fragtree_nolock(f);
113                 BUG();
114         }
115 }
116
117 /*
118  * Check if the flash contains all 0xFF before we start writing.
119  */
120 void
121 __jffs2_dbg_prewrite_paranoia_check(struct jffs2_sb_info *c,
122                                     uint32_t ofs, int len)
123 {
124         size_t retlen;
125         int ret, i;
126         unsigned char *buf;
127
128         buf = kmalloc(len, GFP_KERNEL);
129         if (!buf)
130                 return;
131
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;
138         }
139
140         ret = 0;
141         for (i = 0; i < len; i++)
142                 if (buf[i] != 0xff)
143                         ret = 1;
144
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();
151         }
152
153         kfree(buf);
154 }
155
156 /*
157  * Check the space accounting and node_ref list correctness for the JFFS2 erasable block 'jeb'.
158  */
159 void
160 __jffs2_dbg_acct_paranoia_check(struct jffs2_sb_info *c,
161                                 struct jffs2_eraseblock *jeb)
162 {
163         spin_lock(&c->erase_completion_lock);
164         __jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
165         spin_unlock(&c->erase_completion_lock);
166 }
167
168 void
169 __jffs2_dbg_acct_paranoia_check_nolock(struct jffs2_sb_info *c,
170                                        struct jffs2_eraseblock *jeb)
171 {
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;
176
177         while (ref2) {
178                 uint32_t totlen = ref_totlen(c, jeb, ref2);
179
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;
185
186                 }
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;
193
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;
199                 }
200                 ref2 = ref_next(ref2);
201         }
202
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;
207         }
208
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;
213         }
214
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;
221         }
222
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;
229         }
230 #endif
231
232         return;
233
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();
239
240 }
241 #endif /* JFFS2_DBG_PARANOIA_CHECKS */
242
243 #if defined(JFFS2_DBG_DUMPS) || defined(JFFS2_DBG_PARANOIA_CHECKS)
244 /*
245  * Dump the node_refs of the 'jeb' JFFS2 eraseblock.
246  */
247 void
248 __jffs2_dbg_dump_node_refs(struct jffs2_sb_info *c,
249                            struct jffs2_eraseblock *jeb)
250 {
251         spin_lock(&c->erase_completion_lock);
252         __jffs2_dbg_dump_node_refs_nolock(c, jeb);
253         spin_unlock(&c->erase_completion_lock);
254 }
255
256 void
257 __jffs2_dbg_dump_node_refs_nolock(struct jffs2_sb_info *c,
258                                   struct jffs2_eraseblock *jeb)
259 {
260         struct jffs2_raw_node_ref *ref;
261         int i = 0;
262
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;
267         }
268
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);
279                 }
280         }
281         printk("\n");
282 }
283
284 /*
285  * Dump an eraseblock's space accounting.
286  */
287 void
288 __jffs2_dbg_dump_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
289 {
290         spin_lock(&c->erase_completion_lock);
291         __jffs2_dbg_dump_jeb_nolock(jeb);
292         spin_unlock(&c->erase_completion_lock);
293 }
294
295 void
296 __jffs2_dbg_dump_jeb_nolock(struct jffs2_eraseblock *jeb)
297 {
298         if (!jeb)
299                 return;
300
301         printk(JFFS2_DBG_MSG_PREFIX " dump space accounting for the eraseblock at %#08x:\n",
302                         jeb->offset);
303
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);
309 }
310
311 void
312 __jffs2_dbg_dump_block_lists(struct jffs2_sb_info *c)
313 {
314         spin_lock(&c->erase_completion_lock);
315         __jffs2_dbg_dump_block_lists_nolock(c);
316         spin_unlock(&c->erase_completion_lock);
317 }
318
319 void
320 __jffs2_dbg_dump_block_lists_nolock(struct jffs2_sb_info *c)
321 {
322         printk(JFFS2_DBG_MSG_PREFIX " dump JFFS2 blocks lists:\n");
323
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);
335
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");
343
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");
350
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;
357
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);
366                         }
367                 }
368
369                 printk (JFFS2_DBG "Contains %d blocks with total wasted size %u, average wasted size: %u\n",
370                         numblocks, dirty, dirty / numblocks);
371         }
372
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;
379
380                 list_for_each(this, &c->very_dirty_list) {
381                         struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
382
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);
389                         }
390                 }
391
392                 printk (JFFS2_DBG "Contains %d blocks with total dirty size %u, average dirty size: %u\n",
393                         numblocks, dirty, dirty / numblocks);
394         }
395
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;
402
403                 list_for_each(this, &c->dirty_list) {
404                         struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
405
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);
412                         }
413                 }
414
415                 printk (JFFS2_DBG "contains %d blocks with total dirty size %u, average dirty size: %u\n",
416                         numblocks, dirty, dirty / numblocks);
417         }
418
419         if (list_empty(&c->erasable_list)) {
420                 printk(JFFS2_DBG "erasable_list: empty\n");
421         } else {
422                 struct list_head *this;
423
424                 list_for_each(this, &c->erasable_list) {
425                         struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
426
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);
431                         }
432                 }
433         }
434
435         if (list_empty(&c->erasing_list)) {
436                 printk(JFFS2_DBG "erasing_list: empty\n");
437         } else {
438                 struct list_head *this;
439
440                 list_for_each(this, &c->erasing_list) {
441                         struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
442
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);
447                         }
448                 }
449         }
450
451         if (list_empty(&c->erase_pending_list)) {
452                 printk(JFFS2_DBG "erase_pending_list: empty\n");
453         } else {
454                 struct list_head *this;
455
456                 list_for_each(this, &c->erase_pending_list) {
457                         struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
458
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);
463                         }
464                 }
465         }
466
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;
471
472                 list_for_each(this, &c->erasable_pending_wbuf_list) {
473                         struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
474
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);
479                         }
480                 }
481         }
482
483         if (list_empty(&c->free_list)) {
484                 printk(JFFS2_DBG "free_list: empty\n");
485         } else {
486                 struct list_head *this;
487
488                 list_for_each(this, &c->free_list) {
489                         struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
490
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);
495                         }
496                 }
497         }
498
499         if (list_empty(&c->bad_list)) {
500                 printk(JFFS2_DBG "bad_list: empty\n");
501         } else {
502                 struct list_head *this;
503
504                 list_for_each(this, &c->bad_list) {
505                         struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
506
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);
511                         }
512                 }
513         }
514
515         if (list_empty(&c->bad_used_list)) {
516                 printk(JFFS2_DBG "bad_used_list: empty\n");
517         } else {
518                 struct list_head *this;
519
520                 list_for_each(this, &c->bad_used_list) {
521                         struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
522
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);
527                         }
528                 }
529         }
530 }
531
532 void
533 __jffs2_dbg_dump_fragtree(struct jffs2_inode_info *f)
534 {
535         down(&f->sem);
536         jffs2_dbg_dump_fragtree_nolock(f);
537         up(&f->sem);
538 }
539
540 void
541 __jffs2_dbg_dump_fragtree_nolock(struct jffs2_inode_info *f)
542 {
543         struct jffs2_node_frag *this = frag_first(&f->fragtree);
544         uint32_t lastofs = 0;
545         int buggy = 0;
546
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);
562         }
563
564         if (f->metadata)
565                 printk(JFFS2_DBG "metadata at 0x%08x\n", ref_offset(f->metadata->raw));
566
567         if (buggy) {
568                 JFFS2_ERROR("frag tree got a hole in it.\n");
569                 BUG();
570         }
571 }
572
573 #define JFFS2_BUFDUMP_BYTES_PER_LINE    32
574 void
575 __jffs2_dbg_dump_buffer(unsigned char *buf, int len, uint32_t offs)
576 {
577         int skip;
578         int i;
579
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);
584
585         if (skip != 0)
586                 printk(JFFS2_DBG "%#08x: ", offs);
587
588         while (skip--)
589                 printk("   ");
590
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);
597                 }
598
599                 printk("%02x ", buf[i]);
600
601                 i += 1;
602         }
603
604         printk("\n");
605 }
606
607 /*
608  * Dump a JFFS2 node.
609  */
610 void
611 __jffs2_dbg_dump_node(struct jffs2_sb_info *c, uint32_t ofs)
612 {
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;
618
619         printk(JFFS2_DBG_MSG_PREFIX " dump node at offset %#08x.\n", ofs);
620
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;
626         }
627
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));
632
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;
637         }
638
639         if (je16_to_cpu(node.u.magic) != JFFS2_MAGIC_BITMASK &&
640                 je16_to_cpu(node.u.magic) != JFFS2_OLD_MAGIC_BITMASK)
641         {
642                 JFFS2_ERROR("wrong node magic: %#04x instead of %#04x.\n",
643                         je16_to_cpu(node.u.magic), JFFS2_MAGIC_BITMASK);
644                 return;
645         }
646
647         switch(je16_to_cpu(node.u.nodetype)) {
648
649         case JFFS2_NODETYPE_INODE:
650
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));
669
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;
674                 }
675                 break;
676
677         case JFFS2_NODETYPE_DIRENT:
678
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));
688
689                 node.d.name[node.d.nsize] = '\0';
690                 printk(JFFS2_DBG "name:\t\"%s\"\n", node.d.name);
691
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;
696                 }
697                 break;
698
699         default:
700                 printk(JFFS2_DBG "node type is unknown\n");
701                 break;
702         }
703 }
704 #endif /* JFFS2_DBG_DUMPS || JFFS2_DBG_PARANOIA_CHECKS */