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