Root/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
23void
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
47void
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 */
62void
63__jffs2_dbg_fragtree_paranoia_check(struct jffs2_inode_info *f)
64{
65    mutex_lock(&f->sem);
66    __jffs2_dbg_fragtree_paranoia_check_nolock(f);
67    mutex_unlock(&f->sem);
68}
69
70void
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 */
120void
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
156void __jffs2_dbg_superblock_counts(struct jffs2_sb_info *c)
157{
158    struct jffs2_eraseblock *jeb;
159    uint32_t free = 0, dirty = 0, used = 0, wasted = 0,
160        erasing = 0, bad = 0, unchecked = 0;
161    int nr_counted = 0;
162    int dump = 0;
163
164    if (c->gcblock) {
165        nr_counted++;
166        free += c->gcblock->free_size;
167        dirty += c->gcblock->dirty_size;
168        used += c->gcblock->used_size;
169        wasted += c->gcblock->wasted_size;
170        unchecked += c->gcblock->unchecked_size;
171    }
172    if (c->nextblock) {
173        nr_counted++;
174        free += c->nextblock->free_size;
175        dirty += c->nextblock->dirty_size;
176        used += c->nextblock->used_size;
177        wasted += c->nextblock->wasted_size;
178        unchecked += c->nextblock->unchecked_size;
179    }
180    list_for_each_entry(jeb, &c->clean_list, list) {
181        nr_counted++;
182        free += jeb->free_size;
183        dirty += jeb->dirty_size;
184        used += jeb->used_size;
185        wasted += jeb->wasted_size;
186        unchecked += jeb->unchecked_size;
187    }
188    list_for_each_entry(jeb, &c->very_dirty_list, list) {
189        nr_counted++;
190        free += jeb->free_size;
191        dirty += jeb->dirty_size;
192        used += jeb->used_size;
193        wasted += jeb->wasted_size;
194        unchecked += jeb->unchecked_size;
195    }
196    list_for_each_entry(jeb, &c->dirty_list, list) {
197        nr_counted++;
198        free += jeb->free_size;
199        dirty += jeb->dirty_size;
200        used += jeb->used_size;
201        wasted += jeb->wasted_size;
202        unchecked += jeb->unchecked_size;
203    }
204    list_for_each_entry(jeb, &c->erasable_list, list) {
205        nr_counted++;
206        free += jeb->free_size;
207        dirty += jeb->dirty_size;
208        used += jeb->used_size;
209        wasted += jeb->wasted_size;
210        unchecked += jeb->unchecked_size;
211    }
212    list_for_each_entry(jeb, &c->erasable_pending_wbuf_list, list) {
213        nr_counted++;
214        free += jeb->free_size;
215        dirty += jeb->dirty_size;
216        used += jeb->used_size;
217        wasted += jeb->wasted_size;
218        unchecked += jeb->unchecked_size;
219    }
220    list_for_each_entry(jeb, &c->erase_pending_list, list) {
221        nr_counted++;
222        free += jeb->free_size;
223        dirty += jeb->dirty_size;
224        used += jeb->used_size;
225        wasted += jeb->wasted_size;
226        unchecked += jeb->unchecked_size;
227    }
228    list_for_each_entry(jeb, &c->free_list, list) {
229        nr_counted++;
230        free += jeb->free_size;
231        dirty += jeb->dirty_size;
232        used += jeb->used_size;
233        wasted += jeb->wasted_size;
234        unchecked += jeb->unchecked_size;
235    }
236    list_for_each_entry(jeb, &c->bad_used_list, list) {
237        nr_counted++;
238        free += jeb->free_size;
239        dirty += jeb->dirty_size;
240        used += jeb->used_size;
241        wasted += jeb->wasted_size;
242        unchecked += jeb->unchecked_size;
243    }
244
245    list_for_each_entry(jeb, &c->erasing_list, list) {
246        nr_counted++;
247        erasing += c->sector_size;
248    }
249    list_for_each_entry(jeb, &c->erase_checking_list, list) {
250        nr_counted++;
251        erasing += c->sector_size;
252    }
253    list_for_each_entry(jeb, &c->erase_complete_list, list) {
254        nr_counted++;
255        erasing += c->sector_size;
256    }
257    list_for_each_entry(jeb, &c->bad_list, list) {
258        nr_counted++;
259        bad += c->sector_size;
260    }
261
262#define check(sz) \
263    if (sz != c->sz##_size) { \
264        printk(KERN_WARNING #sz "_size mismatch counted 0x%x, c->" #sz "_size 0x%x\n", \
265               sz, c->sz##_size); \
266        dump = 1; \
267    }
268    check(free);
269    check(dirty);
270    check(used);
271    check(wasted);
272    check(unchecked);
273    check(bad);
274    check(erasing);
275#undef check
276
277    if (nr_counted != c->nr_blocks) {
278        printk(KERN_WARNING "%s counted only 0x%x blocks of 0x%x. Where are the others?\n",
279               __func__, nr_counted, c->nr_blocks);
280        dump = 1;
281    }
282
283    if (dump) {
284        __jffs2_dbg_dump_block_lists_nolock(c);
285        BUG();
286    }
287}
288
289/*
290 * Check the space accounting and node_ref list correctness for the JFFS2 erasable block 'jeb'.
291 */
292void
293__jffs2_dbg_acct_paranoia_check(struct jffs2_sb_info *c,
294                struct jffs2_eraseblock *jeb)
295{
296    spin_lock(&c->erase_completion_lock);
297    __jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
298    spin_unlock(&c->erase_completion_lock);
299}
300
301void
302__jffs2_dbg_acct_paranoia_check_nolock(struct jffs2_sb_info *c,
303                       struct jffs2_eraseblock *jeb)
304{
305    uint32_t my_used_size = 0;
306    uint32_t my_unchecked_size = 0;
307    uint32_t my_dirty_size = 0;
308    struct jffs2_raw_node_ref *ref2 = jeb->first_node;
309
310    while (ref2) {
311        uint32_t totlen = ref_totlen(c, jeb, ref2);
312
313        if (ref_offset(ref2) < jeb->offset ||
314                ref_offset(ref2) > jeb->offset + c->sector_size) {
315            JFFS2_ERROR("node_ref %#08x shouldn't be in block at %#08x.\n",
316                ref_offset(ref2), jeb->offset);
317            goto error;
318
319        }
320        if (ref_flags(ref2) == REF_UNCHECKED)
321            my_unchecked_size += totlen;
322        else if (!ref_obsolete(ref2))
323            my_used_size += totlen;
324        else
325            my_dirty_size += totlen;
326
327        if ((!ref_next(ref2)) != (ref2 == jeb->last_node)) {
328            JFFS2_ERROR("node_ref for node at %#08x (mem %p) has next at %#08x (mem %p), last_node is at %#08x (mem %p).\n",
329                    ref_offset(ref2), ref2, ref_offset(ref_next(ref2)), ref_next(ref2),
330                    ref_offset(jeb->last_node), jeb->last_node);
331            goto error;
332        }
333        ref2 = ref_next(ref2);
334    }
335
336    if (my_used_size != jeb->used_size) {
337        JFFS2_ERROR("Calculated used size %#08x != stored used size %#08x.\n",
338            my_used_size, jeb->used_size);
339        goto error;
340    }
341
342    if (my_unchecked_size != jeb->unchecked_size) {
343        JFFS2_ERROR("Calculated unchecked size %#08x != stored unchecked size %#08x.\n",
344            my_unchecked_size, jeb->unchecked_size);
345        goto error;
346    }
347
348#if 0
349    /* This should work when we implement ref->__totlen elemination */
350    if (my_dirty_size != jeb->dirty_size + jeb->wasted_size) {
351        JFFS2_ERROR("Calculated dirty+wasted size %#08x != stored dirty + wasted size %#08x\n",
352            my_dirty_size, jeb->dirty_size + jeb->wasted_size);
353        goto error;
354    }
355
356    if (jeb->free_size == 0
357        && my_used_size + my_unchecked_size + my_dirty_size != c->sector_size) {
358        JFFS2_ERROR("The sum of all nodes in block (%#x) != size of block (%#x)\n",
359            my_used_size + my_unchecked_size + my_dirty_size,
360            c->sector_size);
361        goto error;
362    }
363#endif
364
365    if (!(c->flags & (JFFS2_SB_FLAG_BUILDING|JFFS2_SB_FLAG_SCANNING)))
366        __jffs2_dbg_superblock_counts(c);
367
368    return;
369
370error:
371    __jffs2_dbg_dump_node_refs_nolock(c, jeb);
372    __jffs2_dbg_dump_jeb_nolock(jeb);
373    __jffs2_dbg_dump_block_lists_nolock(c);
374    BUG();
375
376}
377#endif /* JFFS2_DBG_PARANOIA_CHECKS */
378
379#if defined(JFFS2_DBG_DUMPS) || defined(JFFS2_DBG_PARANOIA_CHECKS)
380/*
381 * Dump the node_refs of the 'jeb' JFFS2 eraseblock.
382 */
383void
384__jffs2_dbg_dump_node_refs(struct jffs2_sb_info *c,
385               struct jffs2_eraseblock *jeb)
386{
387    spin_lock(&c->erase_completion_lock);
388    __jffs2_dbg_dump_node_refs_nolock(c, jeb);
389    spin_unlock(&c->erase_completion_lock);
390}
391
392void
393__jffs2_dbg_dump_node_refs_nolock(struct jffs2_sb_info *c,
394                  struct jffs2_eraseblock *jeb)
395{
396    struct jffs2_raw_node_ref *ref;
397    int i = 0;
398
399    printk(JFFS2_DBG_MSG_PREFIX " Dump node_refs of the eraseblock %#08x\n", jeb->offset);
400    if (!jeb->first_node) {
401        printk(JFFS2_DBG_MSG_PREFIX " no nodes in the eraseblock %#08x\n", jeb->offset);
402        return;
403    }
404
405    printk(JFFS2_DBG);
406    for (ref = jeb->first_node; ; ref = ref_next(ref)) {
407        printk("%#08x", ref_offset(ref));
408#ifdef TEST_TOTLEN
409        printk("(%x)", ref->__totlen);
410#endif
411        if (ref_next(ref))
412            printk("->");
413        else
414            break;
415        if (++i == 4) {
416            i = 0;
417            printk("\n" JFFS2_DBG);
418        }
419    }
420    printk("\n");
421}
422
423/*
424 * Dump an eraseblock's space accounting.
425 */
426void
427__jffs2_dbg_dump_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
428{
429    spin_lock(&c->erase_completion_lock);
430    __jffs2_dbg_dump_jeb_nolock(jeb);
431    spin_unlock(&c->erase_completion_lock);
432}
433
434void
435__jffs2_dbg_dump_jeb_nolock(struct jffs2_eraseblock *jeb)
436{
437    if (!jeb)
438        return;
439
440    printk(JFFS2_DBG_MSG_PREFIX " dump space accounting for the eraseblock at %#08x:\n",
441            jeb->offset);
442
443    printk(JFFS2_DBG "used_size: %#08x\n", jeb->used_size);
444    printk(JFFS2_DBG "dirty_size: %#08x\n", jeb->dirty_size);
445    printk(JFFS2_DBG "wasted_size: %#08x\n", jeb->wasted_size);
446    printk(JFFS2_DBG "unchecked_size: %#08x\n", jeb->unchecked_size);
447    printk(JFFS2_DBG "free_size: %#08x\n", jeb->free_size);
448}
449
450void
451__jffs2_dbg_dump_block_lists(struct jffs2_sb_info *c)
452{
453    spin_lock(&c->erase_completion_lock);
454    __jffs2_dbg_dump_block_lists_nolock(c);
455    spin_unlock(&c->erase_completion_lock);
456}
457
458void
459__jffs2_dbg_dump_block_lists_nolock(struct jffs2_sb_info *c)
460{
461    printk(JFFS2_DBG_MSG_PREFIX " dump JFFS2 blocks lists:\n");
462
463    printk(JFFS2_DBG "flash_size: %#08x\n", c->flash_size);
464    printk(JFFS2_DBG "used_size: %#08x\n", c->used_size);
465    printk(JFFS2_DBG "dirty_size: %#08x\n", c->dirty_size);
466    printk(JFFS2_DBG "wasted_size: %#08x\n", c->wasted_size);
467    printk(JFFS2_DBG "unchecked_size: %#08x\n", c->unchecked_size);
468    printk(JFFS2_DBG "free_size: %#08x\n", c->free_size);
469    printk(JFFS2_DBG "erasing_size: %#08x\n", c->erasing_size);
470    printk(JFFS2_DBG "bad_size: %#08x\n", c->bad_size);
471    printk(JFFS2_DBG "sector_size: %#08x\n", c->sector_size);
472    printk(JFFS2_DBG "jffs2_reserved_blocks size: %#08x\n",
473                c->sector_size * c->resv_blocks_write);
474
475    if (c->nextblock)
476        printk(JFFS2_DBG "nextblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
477            c->nextblock->offset, c->nextblock->used_size,
478            c->nextblock->dirty_size, c->nextblock->wasted_size,
479            c->nextblock->unchecked_size, c->nextblock->free_size);
480    else
481        printk(JFFS2_DBG "nextblock: NULL\n");
482
483    if (c->gcblock)
484        printk(JFFS2_DBG "gcblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
485            c->gcblock->offset, c->gcblock->used_size, c->gcblock->dirty_size,
486            c->gcblock->wasted_size, c->gcblock->unchecked_size, c->gcblock->free_size);
487    else
488        printk(JFFS2_DBG "gcblock: NULL\n");
489
490    if (list_empty(&c->clean_list)) {
491        printk(JFFS2_DBG "clean_list: empty\n");
492    } else {
493        struct list_head *this;
494        int numblocks = 0;
495        uint32_t dirty = 0;
496
497        list_for_each(this, &c->clean_list) {
498            struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
499            numblocks ++;
500            dirty += jeb->wasted_size;
501            if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
502                printk(JFFS2_DBG "clean_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
503                    jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
504                    jeb->unchecked_size, jeb->free_size);
505            }
506        }
507
508        printk (JFFS2_DBG "Contains %d blocks with total wasted size %u, average wasted size: %u\n",
509            numblocks, dirty, dirty / numblocks);
510    }
511
512    if (list_empty(&c->very_dirty_list)) {
513        printk(JFFS2_DBG "very_dirty_list: empty\n");
514    } else {
515        struct list_head *this;
516        int numblocks = 0;
517        uint32_t dirty = 0;
518
519        list_for_each(this, &c->very_dirty_list) {
520            struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
521
522            numblocks ++;
523            dirty += jeb->dirty_size;
524            if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
525                printk(JFFS2_DBG "very_dirty_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        printk (JFFS2_DBG "Contains %d blocks with total dirty size %u, average dirty size: %u\n",
532            numblocks, dirty, dirty / numblocks);
533    }
534
535    if (list_empty(&c->dirty_list)) {
536        printk(JFFS2_DBG "dirty_list: empty\n");
537    } else {
538        struct list_head *this;
539        int numblocks = 0;
540        uint32_t dirty = 0;
541
542        list_for_each(this, &c->dirty_list) {
543            struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
544
545            numblocks ++;
546            dirty += jeb->dirty_size;
547            if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
548                printk(JFFS2_DBG "dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
549                    jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
550                    jeb->unchecked_size, jeb->free_size);
551            }
552        }
553
554        printk (JFFS2_DBG "contains %d blocks with total dirty size %u, average dirty size: %u\n",
555            numblocks, dirty, dirty / numblocks);
556    }
557
558    if (list_empty(&c->erasable_list)) {
559        printk(JFFS2_DBG "erasable_list: empty\n");
560    } else {
561        struct list_head *this;
562
563        list_for_each(this, &c->erasable_list) {
564            struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
565
566            if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
567                printk(JFFS2_DBG "erasable_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
568                    jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
569                    jeb->unchecked_size, jeb->free_size);
570            }
571        }
572    }
573
574    if (list_empty(&c->erasing_list)) {
575        printk(JFFS2_DBG "erasing_list: empty\n");
576    } else {
577        struct list_head *this;
578
579        list_for_each(this, &c->erasing_list) {
580            struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
581
582            if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
583                printk(JFFS2_DBG "erasing_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
584                    jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
585                    jeb->unchecked_size, jeb->free_size);
586            }
587        }
588    }
589    if (list_empty(&c->erase_checking_list)) {
590        printk(JFFS2_DBG "erase_checking_list: empty\n");
591    } else {
592        struct list_head *this;
593
594        list_for_each(this, &c->erase_checking_list) {
595            struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
596
597            if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
598                printk(JFFS2_DBG "erase_checking_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
599                    jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
600                    jeb->unchecked_size, jeb->free_size);
601            }
602        }
603    }
604
605    if (list_empty(&c->erase_pending_list)) {
606        printk(JFFS2_DBG "erase_pending_list: empty\n");
607    } else {
608        struct list_head *this;
609
610        list_for_each(this, &c->erase_pending_list) {
611            struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
612
613            if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
614                printk(JFFS2_DBG "erase_pending_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
615                    jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
616                    jeb->unchecked_size, jeb->free_size);
617            }
618        }
619    }
620
621    if (list_empty(&c->erasable_pending_wbuf_list)) {
622        printk(JFFS2_DBG "erasable_pending_wbuf_list: empty\n");
623    } else {
624        struct list_head *this;
625
626        list_for_each(this, &c->erasable_pending_wbuf_list) {
627            struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
628
629            if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
630                printk(JFFS2_DBG "erasable_pending_wbuf_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
631                    jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
632                    jeb->unchecked_size, jeb->free_size);
633            }
634        }
635    }
636
637    if (list_empty(&c->free_list)) {
638        printk(JFFS2_DBG "free_list: empty\n");
639    } else {
640        struct list_head *this;
641
642        list_for_each(this, &c->free_list) {
643            struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
644
645            if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
646                printk(JFFS2_DBG "free_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
647                    jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
648                    jeb->unchecked_size, jeb->free_size);
649            }
650        }
651    }
652
653    if (list_empty(&c->bad_list)) {
654        printk(JFFS2_DBG "bad_list: empty\n");
655    } else {
656        struct list_head *this;
657
658        list_for_each(this, &c->bad_list) {
659            struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
660
661            if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
662                printk(JFFS2_DBG "bad_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
663                    jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
664                    jeb->unchecked_size, jeb->free_size);
665            }
666        }
667    }
668
669    if (list_empty(&c->bad_used_list)) {
670        printk(JFFS2_DBG "bad_used_list: empty\n");
671    } else {
672        struct list_head *this;
673
674        list_for_each(this, &c->bad_used_list) {
675            struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
676
677            if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
678                printk(JFFS2_DBG "bad_used_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
679                    jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
680                    jeb->unchecked_size, jeb->free_size);
681            }
682        }
683    }
684}
685
686void
687__jffs2_dbg_dump_fragtree(struct jffs2_inode_info *f)
688{
689    mutex_lock(&f->sem);
690    jffs2_dbg_dump_fragtree_nolock(f);
691    mutex_unlock(&f->sem);
692}
693
694void
695__jffs2_dbg_dump_fragtree_nolock(struct jffs2_inode_info *f)
696{
697    struct jffs2_node_frag *this = frag_first(&f->fragtree);
698    uint32_t lastofs = 0;
699    int buggy = 0;
700
701    printk(JFFS2_DBG_MSG_PREFIX " dump fragtree of ino #%u\n", f->inocache->ino);
702    while(this) {
703        if (this->node)
704            printk(JFFS2_DBG "frag %#04x-%#04x: %#08x(%d) on flash (*%p), left (%p), right (%p), parent (%p)\n",
705                this->ofs, this->ofs+this->size, ref_offset(this->node->raw),
706                ref_flags(this->node->raw), this, frag_left(this), frag_right(this),
707                frag_parent(this));
708        else
709            printk(JFFS2_DBG "frag %#04x-%#04x: hole (*%p). left (%p), right (%p), parent (%p)\n",
710                this->ofs, this->ofs+this->size, this, frag_left(this),
711                frag_right(this), frag_parent(this));
712        if (this->ofs != lastofs)
713            buggy = 1;
714        lastofs = this->ofs + this->size;
715        this = frag_next(this);
716    }
717
718    if (f->metadata)
719        printk(JFFS2_DBG "metadata at 0x%08x\n", ref_offset(f->metadata->raw));
720
721    if (buggy) {
722        JFFS2_ERROR("frag tree got a hole in it.\n");
723        BUG();
724    }
725}
726
727#define JFFS2_BUFDUMP_BYTES_PER_LINE 32
728void
729__jffs2_dbg_dump_buffer(unsigned char *buf, int len, uint32_t offs)
730{
731    int skip;
732    int i;
733
734    printk(JFFS2_DBG_MSG_PREFIX " dump from offset %#08x to offset %#08x (%x bytes).\n",
735        offs, offs + len, len);
736    i = skip = offs % JFFS2_BUFDUMP_BYTES_PER_LINE;
737    offs = offs & ~(JFFS2_BUFDUMP_BYTES_PER_LINE - 1);
738
739    if (skip != 0)
740        printk(JFFS2_DBG "%#08x: ", offs);
741
742    while (skip--)
743        printk(" ");
744
745    while (i < len) {
746        if ((i % JFFS2_BUFDUMP_BYTES_PER_LINE) == 0 && i != len -1) {
747            if (i != 0)
748                printk("\n");
749            offs += JFFS2_BUFDUMP_BYTES_PER_LINE;
750            printk(JFFS2_DBG "%0#8x: ", offs);
751        }
752
753        printk("%02x ", buf[i]);
754
755        i += 1;
756    }
757
758    printk("\n");
759}
760
761/*
762 * Dump a JFFS2 node.
763 */
764void
765__jffs2_dbg_dump_node(struct jffs2_sb_info *c, uint32_t ofs)
766{
767    union jffs2_node_union node;
768    int len = sizeof(union jffs2_node_union);
769    size_t retlen;
770    uint32_t crc;
771    int ret;
772
773    printk(JFFS2_DBG_MSG_PREFIX " dump node at offset %#08x.\n", ofs);
774
775    ret = jffs2_flash_read(c, ofs, len, &retlen, (unsigned char *)&node);
776    if (ret || (retlen != len)) {
777        JFFS2_ERROR("read %d bytes failed or short. ret %d, retlen %zd.\n",
778            len, ret, retlen);
779        return;
780    }
781
782    printk(JFFS2_DBG "magic:\t%#04x\n", je16_to_cpu(node.u.magic));
783    printk(JFFS2_DBG "nodetype:\t%#04x\n", je16_to_cpu(node.u.nodetype));
784    printk(JFFS2_DBG "totlen:\t%#08x\n", je32_to_cpu(node.u.totlen));
785    printk(JFFS2_DBG "hdr_crc:\t%#08x\n", je32_to_cpu(node.u.hdr_crc));
786
787    crc = crc32(0, &node.u, sizeof(node.u) - 4);
788    if (crc != je32_to_cpu(node.u.hdr_crc)) {
789        JFFS2_ERROR("wrong common header CRC.\n");
790        return;
791    }
792
793    if (je16_to_cpu(node.u.magic) != JFFS2_MAGIC_BITMASK &&
794        je16_to_cpu(node.u.magic) != JFFS2_OLD_MAGIC_BITMASK)
795    {
796        JFFS2_ERROR("wrong node magic: %#04x instead of %#04x.\n",
797            je16_to_cpu(node.u.magic), JFFS2_MAGIC_BITMASK);
798        return;
799    }
800
801    switch(je16_to_cpu(node.u.nodetype)) {
802
803    case JFFS2_NODETYPE_INODE:
804
805        printk(JFFS2_DBG "the node is inode node\n");
806        printk(JFFS2_DBG "ino:\t%#08x\n", je32_to_cpu(node.i.ino));
807        printk(JFFS2_DBG "version:\t%#08x\n", je32_to_cpu(node.i.version));
808        printk(JFFS2_DBG "mode:\t%#08x\n", node.i.mode.m);
809        printk(JFFS2_DBG "uid:\t%#04x\n", je16_to_cpu(node.i.uid));
810        printk(JFFS2_DBG "gid:\t%#04x\n", je16_to_cpu(node.i.gid));
811        printk(JFFS2_DBG "isize:\t%#08x\n", je32_to_cpu(node.i.isize));
812        printk(JFFS2_DBG "atime:\t%#08x\n", je32_to_cpu(node.i.atime));
813        printk(JFFS2_DBG "mtime:\t%#08x\n", je32_to_cpu(node.i.mtime));
814        printk(JFFS2_DBG "ctime:\t%#08x\n", je32_to_cpu(node.i.ctime));
815        printk(JFFS2_DBG "offset:\t%#08x\n", je32_to_cpu(node.i.offset));
816        printk(JFFS2_DBG "csize:\t%#08x\n", je32_to_cpu(node.i.csize));
817        printk(JFFS2_DBG "dsize:\t%#08x\n", je32_to_cpu(node.i.dsize));
818        printk(JFFS2_DBG "compr:\t%#02x\n", node.i.compr);
819        printk(JFFS2_DBG "usercompr:\t%#02x\n", node.i.usercompr);
820        printk(JFFS2_DBG "flags:\t%#04x\n", je16_to_cpu(node.i.flags));
821        printk(JFFS2_DBG "data_crc:\t%#08x\n", je32_to_cpu(node.i.data_crc));
822        printk(JFFS2_DBG "node_crc:\t%#08x\n", je32_to_cpu(node.i.node_crc));
823
824        crc = crc32(0, &node.i, sizeof(node.i) - 8);
825        if (crc != je32_to_cpu(node.i.node_crc)) {
826            JFFS2_ERROR("wrong node header CRC.\n");
827            return;
828        }
829        break;
830
831    case JFFS2_NODETYPE_DIRENT:
832
833        printk(JFFS2_DBG "the node is dirent node\n");
834        printk(JFFS2_DBG "pino:\t%#08x\n", je32_to_cpu(node.d.pino));
835        printk(JFFS2_DBG "version:\t%#08x\n", je32_to_cpu(node.d.version));
836        printk(JFFS2_DBG "ino:\t%#08x\n", je32_to_cpu(node.d.ino));
837        printk(JFFS2_DBG "mctime:\t%#08x\n", je32_to_cpu(node.d.mctime));
838        printk(JFFS2_DBG "nsize:\t%#02x\n", node.d.nsize);
839        printk(JFFS2_DBG "type:\t%#02x\n", node.d.type);
840        printk(JFFS2_DBG "node_crc:\t%#08x\n", je32_to_cpu(node.d.node_crc));
841        printk(JFFS2_DBG "name_crc:\t%#08x\n", je32_to_cpu(node.d.name_crc));
842
843        node.d.name[node.d.nsize] = '\0';
844        printk(JFFS2_DBG "name:\t\"%s\"\n", node.d.name);
845
846        crc = crc32(0, &node.d, sizeof(node.d) - 8);
847        if (crc != je32_to_cpu(node.d.node_crc)) {
848            JFFS2_ERROR("wrong node header CRC.\n");
849            return;
850        }
851        break;
852
853    default:
854        printk(JFFS2_DBG "node type is unknown\n");
855        break;
856    }
857}
858#endif /* JFFS2_DBG_DUMPS || JFFS2_DBG_PARANOIA_CHECKS */
859

Archive Download this file



interactive