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