Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * JFFS2 -- Journalling Flash File System, Version 2.
0003  *
0004  * Copyright © 2001-2007 Red Hat, Inc.
0005  * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org>
0006  *
0007  * Created by David Woodhouse <dwmw2@infradead.org>
0008  *
0009  * For licensing information, see the file 'LICENCE' in this directory.
0010  *
0011  */
0012 
0013 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0014 
0015 #include <linux/kernel.h>
0016 #include <linux/types.h>
0017 #include <linux/pagemap.h>
0018 #include <linux/crc32.h>
0019 #include <linux/jffs2.h>
0020 #include <linux/mtd/mtd.h>
0021 #include <linux/slab.h>
0022 #include "nodelist.h"
0023 #include "debug.h"
0024 
0025 #ifdef JFFS2_DBG_SANITY_CHECKS
0026 
0027 void
0028 __jffs2_dbg_acct_sanity_check_nolock(struct jffs2_sb_info *c,
0029                      struct jffs2_eraseblock *jeb)
0030 {
0031     if (unlikely(jeb && jeb->used_size + jeb->dirty_size +
0032             jeb->free_size + jeb->wasted_size +
0033             jeb->unchecked_size != c->sector_size)) {
0034         JFFS2_ERROR("eeep, space accounting for block at 0x%08x is screwed.\n", jeb->offset);
0035         JFFS2_ERROR("free %#08x + dirty %#08x + used %#08x + wasted %#08x + unchecked %#08x != total %#08x.\n",
0036             jeb->free_size, jeb->dirty_size, jeb->used_size,
0037             jeb->wasted_size, jeb->unchecked_size, c->sector_size);
0038         BUG();
0039     }
0040 
0041     if (unlikely(c->used_size + c->dirty_size + c->free_size + c->erasing_size + c->bad_size
0042                 + c->wasted_size + c->unchecked_size != c->flash_size)) {
0043         JFFS2_ERROR("eeep, space accounting superblock info is screwed.\n");
0044         JFFS2_ERROR("free %#08x + dirty %#08x + used %#08x + erasing %#08x + bad %#08x + wasted %#08x + unchecked %#08x != total %#08x.\n",
0045             c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size,
0046             c->wasted_size, c->unchecked_size, c->flash_size);
0047         BUG();
0048     }
0049 }
0050 
0051 void
0052 __jffs2_dbg_acct_sanity_check(struct jffs2_sb_info *c,
0053                   struct jffs2_eraseblock *jeb)
0054 {
0055     spin_lock(&c->erase_completion_lock);
0056     jffs2_dbg_acct_sanity_check_nolock(c, jeb);
0057     spin_unlock(&c->erase_completion_lock);
0058 }
0059 
0060 #endif /* JFFS2_DBG_SANITY_CHECKS */
0061 
0062 #ifdef JFFS2_DBG_PARANOIA_CHECKS
0063 /*
0064  * Check the fragtree.
0065  */
0066 void
0067 __jffs2_dbg_fragtree_paranoia_check(struct jffs2_inode_info *f)
0068 {
0069     mutex_lock(&f->sem);
0070     __jffs2_dbg_fragtree_paranoia_check_nolock(f);
0071     mutex_unlock(&f->sem);
0072 }
0073 
0074 void
0075 __jffs2_dbg_fragtree_paranoia_check_nolock(struct jffs2_inode_info *f)
0076 {
0077     struct jffs2_node_frag *frag;
0078     int bitched = 0;
0079 
0080     for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) {
0081         struct jffs2_full_dnode *fn = frag->node;
0082 
0083         if (!fn || !fn->raw)
0084             continue;
0085 
0086         if (ref_flags(fn->raw) == REF_PRISTINE) {
0087             if (fn->frags > 1) {
0088                 JFFS2_ERROR("REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2.\n",
0089                     ref_offset(fn->raw), fn->frags);
0090                 bitched = 1;
0091             }
0092 
0093             /* A hole node which isn't multi-page should be garbage-collected
0094                and merged anyway, so we just check for the frag size here,
0095                rather than mucking around with actually reading the node
0096                and checking the compression type, which is the real way
0097                to tell a hole node. */
0098             if (frag->ofs & (PAGE_SIZE-1) && frag_prev(frag)
0099                     && frag_prev(frag)->size < PAGE_SIZE && frag_prev(frag)->node) {
0100                 JFFS2_ERROR("REF_PRISTINE node at 0x%08x had a previous non-hole frag in the same page. Tell dwmw2.\n",
0101                     ref_offset(fn->raw));
0102                 bitched = 1;
0103             }
0104 
0105             if ((frag->ofs+frag->size) & (PAGE_SIZE-1) && frag_next(frag)
0106                     && frag_next(frag)->size < PAGE_SIZE && frag_next(frag)->node) {
0107                 JFFS2_ERROR("REF_PRISTINE node at 0x%08x (%08x-%08x) had a following non-hole frag in the same page. Tell dwmw2.\n",
0108                        ref_offset(fn->raw), frag->ofs, frag->ofs+frag->size);
0109                 bitched = 1;
0110             }
0111         }
0112     }
0113 
0114     if (bitched) {
0115         JFFS2_ERROR("fragtree is corrupted.\n");
0116         __jffs2_dbg_dump_fragtree_nolock(f);
0117         BUG();
0118     }
0119 }
0120 
0121 /*
0122  * Check if the flash contains all 0xFF before we start writing.
0123  */
0124 void
0125 __jffs2_dbg_prewrite_paranoia_check(struct jffs2_sb_info *c,
0126                     uint32_t ofs, int len)
0127 {
0128     size_t retlen;
0129     int ret, i;
0130     unsigned char *buf;
0131 
0132     buf = kmalloc(len, GFP_KERNEL);
0133     if (!buf)
0134         return;
0135 
0136     ret = jffs2_flash_read(c, ofs, len, &retlen, buf);
0137     if (ret || (retlen != len)) {
0138         JFFS2_WARNING("read %d bytes failed or short. ret %d, retlen %zd.\n",
0139                 len, ret, retlen);
0140         kfree(buf);
0141         return;
0142     }
0143 
0144     ret = 0;
0145     for (i = 0; i < len; i++)
0146         if (buf[i] != 0xff)
0147             ret = 1;
0148 
0149     if (ret) {
0150         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",
0151             ofs, ofs + i);
0152         __jffs2_dbg_dump_buffer(buf, len, ofs);
0153         kfree(buf);
0154         BUG();
0155     }
0156 
0157     kfree(buf);
0158 }
0159 
0160 void __jffs2_dbg_superblock_counts(struct jffs2_sb_info *c)
0161 {
0162     struct jffs2_eraseblock *jeb;
0163     uint32_t free = 0, dirty = 0, used = 0, wasted = 0,
0164         erasing = 0, bad = 0, unchecked = 0;
0165     int nr_counted = 0;
0166     int dump = 0;
0167 
0168     if (c->gcblock) {
0169         nr_counted++;
0170         free += c->gcblock->free_size;
0171         dirty += c->gcblock->dirty_size;
0172         used += c->gcblock->used_size;
0173         wasted += c->gcblock->wasted_size;
0174         unchecked += c->gcblock->unchecked_size;
0175     }
0176     if (c->nextblock) {
0177         nr_counted++;
0178         free += c->nextblock->free_size;
0179         dirty += c->nextblock->dirty_size;
0180         used += c->nextblock->used_size;
0181         wasted += c->nextblock->wasted_size;
0182         unchecked += c->nextblock->unchecked_size;
0183     }
0184     list_for_each_entry(jeb, &c->clean_list, list) {
0185         nr_counted++;
0186         free += jeb->free_size;
0187         dirty += jeb->dirty_size;
0188         used += jeb->used_size;
0189         wasted += jeb->wasted_size;
0190         unchecked += jeb->unchecked_size;
0191     }
0192     list_for_each_entry(jeb, &c->very_dirty_list, list) {
0193         nr_counted++;
0194         free += jeb->free_size;
0195         dirty += jeb->dirty_size;
0196         used += jeb->used_size;
0197         wasted += jeb->wasted_size;
0198         unchecked += jeb->unchecked_size;
0199     }
0200     list_for_each_entry(jeb, &c->dirty_list, list) {
0201         nr_counted++;
0202         free += jeb->free_size;
0203         dirty += jeb->dirty_size;
0204         used += jeb->used_size;
0205         wasted += jeb->wasted_size;
0206         unchecked += jeb->unchecked_size;
0207     }
0208     list_for_each_entry(jeb, &c->erasable_list, list) {
0209         nr_counted++;
0210         free += jeb->free_size;
0211         dirty += jeb->dirty_size;
0212         used += jeb->used_size;
0213         wasted += jeb->wasted_size;
0214         unchecked += jeb->unchecked_size;
0215     }
0216     list_for_each_entry(jeb, &c->erasable_pending_wbuf_list, list) {
0217         nr_counted++;
0218         free += jeb->free_size;
0219         dirty += jeb->dirty_size;
0220         used += jeb->used_size;
0221         wasted += jeb->wasted_size;
0222         unchecked += jeb->unchecked_size;
0223     }
0224     list_for_each_entry(jeb, &c->erase_pending_list, list) {
0225         nr_counted++;
0226         free += jeb->free_size;
0227         dirty += jeb->dirty_size;
0228         used += jeb->used_size;
0229         wasted += jeb->wasted_size;
0230         unchecked += jeb->unchecked_size;
0231     }
0232     list_for_each_entry(jeb, &c->free_list, list) {
0233         nr_counted++;
0234         free += jeb->free_size;
0235         dirty += jeb->dirty_size;
0236         used += jeb->used_size;
0237         wasted += jeb->wasted_size;
0238         unchecked += jeb->unchecked_size;
0239     }
0240     list_for_each_entry(jeb, &c->bad_used_list, list) {
0241         nr_counted++;
0242         free += jeb->free_size;
0243         dirty += jeb->dirty_size;
0244         used += jeb->used_size;
0245         wasted += jeb->wasted_size;
0246         unchecked += jeb->unchecked_size;
0247     }
0248 
0249     list_for_each_entry(jeb, &c->erasing_list, list) {
0250         nr_counted++;
0251         erasing += c->sector_size;
0252     }
0253     list_for_each_entry(jeb, &c->erase_checking_list, list) {
0254         nr_counted++;
0255         erasing += c->sector_size;
0256     }
0257     list_for_each_entry(jeb, &c->erase_complete_list, list) {
0258         nr_counted++;
0259         erasing += c->sector_size;
0260     }
0261     list_for_each_entry(jeb, &c->bad_list, list) {
0262         nr_counted++;
0263         bad += c->sector_size;
0264     }
0265 
0266 #define check(sz)                           \
0267 do {                                    \
0268     if (sz != c->sz##_size) {                   \
0269         pr_warn("%s_size mismatch counted 0x%x, c->%s_size 0x%x\n", \
0270             #sz, sz, #sz, c->sz##_size);            \
0271         dump = 1;                       \
0272     }                               \
0273 } while (0)
0274 
0275     check(free);
0276     check(dirty);
0277     check(used);
0278     check(wasted);
0279     check(unchecked);
0280     check(bad);
0281     check(erasing);
0282 
0283 #undef check
0284 
0285     if (nr_counted != c->nr_blocks) {
0286         pr_warn("%s counted only 0x%x blocks of 0x%x. Where are the others?\n",
0287             __func__, nr_counted, c->nr_blocks);
0288         dump = 1;
0289     }
0290 
0291     if (dump) {
0292         __jffs2_dbg_dump_block_lists_nolock(c);
0293         BUG();
0294     }
0295 }
0296 
0297 /*
0298  * Check the space accounting and node_ref list correctness for the JFFS2 erasable block 'jeb'.
0299  */
0300 void
0301 __jffs2_dbg_acct_paranoia_check(struct jffs2_sb_info *c,
0302                 struct jffs2_eraseblock *jeb)
0303 {
0304     spin_lock(&c->erase_completion_lock);
0305     __jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
0306     spin_unlock(&c->erase_completion_lock);
0307 }
0308 
0309 void
0310 __jffs2_dbg_acct_paranoia_check_nolock(struct jffs2_sb_info *c,
0311                        struct jffs2_eraseblock *jeb)
0312 {
0313     uint32_t my_used_size = 0;
0314     uint32_t my_unchecked_size = 0;
0315     uint32_t my_dirty_size = 0;
0316     struct jffs2_raw_node_ref *ref2 = jeb->first_node;
0317 
0318     while (ref2) {
0319         uint32_t totlen = ref_totlen(c, jeb, ref2);
0320 
0321         if (ref_offset(ref2) < jeb->offset ||
0322                 ref_offset(ref2) > jeb->offset + c->sector_size) {
0323             JFFS2_ERROR("node_ref %#08x shouldn't be in block at %#08x.\n",
0324                 ref_offset(ref2), jeb->offset);
0325             goto error;
0326 
0327         }
0328         if (ref_flags(ref2) == REF_UNCHECKED)
0329             my_unchecked_size += totlen;
0330         else if (!ref_obsolete(ref2))
0331             my_used_size += totlen;
0332         else
0333             my_dirty_size += totlen;
0334 
0335         if ((!ref_next(ref2)) != (ref2 == jeb->last_node)) {
0336             JFFS2_ERROR("node_ref for node at %#08x (mem %p) has next at %#08x (mem %p), last_node is at %#08x (mem %p).\n",
0337                     ref_offset(ref2), ref2, ref_offset(ref_next(ref2)), ref_next(ref2),
0338                     ref_offset(jeb->last_node), jeb->last_node);
0339             goto error;
0340         }
0341         ref2 = ref_next(ref2);
0342     }
0343 
0344     if (my_used_size != jeb->used_size) {
0345         JFFS2_ERROR("Calculated used size %#08x != stored used size %#08x.\n",
0346             my_used_size, jeb->used_size);
0347         goto error;
0348     }
0349 
0350     if (my_unchecked_size != jeb->unchecked_size) {
0351         JFFS2_ERROR("Calculated unchecked size %#08x != stored unchecked size %#08x.\n",
0352             my_unchecked_size, jeb->unchecked_size);
0353         goto error;
0354     }
0355 
0356 #if 0
0357     /* This should work when we implement ref->__totlen elemination */
0358     if (my_dirty_size != jeb->dirty_size + jeb->wasted_size) {
0359         JFFS2_ERROR("Calculated dirty+wasted size %#08x != stored dirty + wasted size %#08x\n",
0360             my_dirty_size, jeb->dirty_size + jeb->wasted_size);
0361         goto error;
0362     }
0363 
0364     if (jeb->free_size == 0
0365         && my_used_size + my_unchecked_size + my_dirty_size != c->sector_size) {
0366         JFFS2_ERROR("The sum of all nodes in block (%#x) != size of block (%#x)\n",
0367             my_used_size + my_unchecked_size + my_dirty_size,
0368             c->sector_size);
0369         goto error;
0370     }
0371 #endif
0372 
0373     if (!(c->flags & (JFFS2_SB_FLAG_BUILDING|JFFS2_SB_FLAG_SCANNING)))
0374         __jffs2_dbg_superblock_counts(c);
0375 
0376     return;
0377 
0378 error:
0379     __jffs2_dbg_dump_node_refs_nolock(c, jeb);
0380     __jffs2_dbg_dump_jeb_nolock(jeb);
0381     __jffs2_dbg_dump_block_lists_nolock(c);
0382     BUG();
0383 
0384 }
0385 #endif /* JFFS2_DBG_PARANOIA_CHECKS */
0386 
0387 #if defined(JFFS2_DBG_DUMPS) || defined(JFFS2_DBG_PARANOIA_CHECKS)
0388 /*
0389  * Dump the node_refs of the 'jeb' JFFS2 eraseblock.
0390  */
0391 void
0392 __jffs2_dbg_dump_node_refs(struct jffs2_sb_info *c,
0393                struct jffs2_eraseblock *jeb)
0394 {
0395     spin_lock(&c->erase_completion_lock);
0396     __jffs2_dbg_dump_node_refs_nolock(c, jeb);
0397     spin_unlock(&c->erase_completion_lock);
0398 }
0399 
0400 void
0401 __jffs2_dbg_dump_node_refs_nolock(struct jffs2_sb_info *c,
0402                   struct jffs2_eraseblock *jeb)
0403 {
0404     struct jffs2_raw_node_ref *ref;
0405     int i = 0;
0406 
0407     printk(JFFS2_DBG_MSG_PREFIX " Dump node_refs of the eraseblock %#08x\n", jeb->offset);
0408     if (!jeb->first_node) {
0409         printk(JFFS2_DBG_MSG_PREFIX " no nodes in the eraseblock %#08x\n", jeb->offset);
0410         return;
0411     }
0412 
0413     printk(JFFS2_DBG);
0414     for (ref = jeb->first_node; ; ref = ref_next(ref)) {
0415         printk("%#08x", ref_offset(ref));
0416 #ifdef TEST_TOTLEN
0417         printk("(%x)", ref->__totlen);
0418 #endif
0419         if (ref_next(ref))
0420             printk("->");
0421         else
0422             break;
0423         if (++i == 4) {
0424             i = 0;
0425             printk("\n" JFFS2_DBG);
0426         }
0427     }
0428     printk("\n");
0429 }
0430 
0431 /*
0432  * Dump an eraseblock's space accounting.
0433  */
0434 void
0435 __jffs2_dbg_dump_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
0436 {
0437     spin_lock(&c->erase_completion_lock);
0438     __jffs2_dbg_dump_jeb_nolock(jeb);
0439     spin_unlock(&c->erase_completion_lock);
0440 }
0441 
0442 void
0443 __jffs2_dbg_dump_jeb_nolock(struct jffs2_eraseblock *jeb)
0444 {
0445     if (!jeb)
0446         return;
0447 
0448     printk(JFFS2_DBG_MSG_PREFIX " dump space accounting for the eraseblock at %#08x:\n",
0449             jeb->offset);
0450 
0451     printk(JFFS2_DBG "used_size: %#08x\n",      jeb->used_size);
0452     printk(JFFS2_DBG "dirty_size: %#08x\n",     jeb->dirty_size);
0453     printk(JFFS2_DBG "wasted_size: %#08x\n",    jeb->wasted_size);
0454     printk(JFFS2_DBG "unchecked_size: %#08x\n", jeb->unchecked_size);
0455     printk(JFFS2_DBG "free_size: %#08x\n",      jeb->free_size);
0456 }
0457 
0458 void
0459 __jffs2_dbg_dump_block_lists(struct jffs2_sb_info *c)
0460 {
0461     spin_lock(&c->erase_completion_lock);
0462     __jffs2_dbg_dump_block_lists_nolock(c);
0463     spin_unlock(&c->erase_completion_lock);
0464 }
0465 
0466 void
0467 __jffs2_dbg_dump_block_lists_nolock(struct jffs2_sb_info *c)
0468 {
0469     printk(JFFS2_DBG_MSG_PREFIX " dump JFFS2 blocks lists:\n");
0470 
0471     printk(JFFS2_DBG "flash_size: %#08x\n",     c->flash_size);
0472     printk(JFFS2_DBG "used_size: %#08x\n",      c->used_size);
0473     printk(JFFS2_DBG "dirty_size: %#08x\n",     c->dirty_size);
0474     printk(JFFS2_DBG "wasted_size: %#08x\n",    c->wasted_size);
0475     printk(JFFS2_DBG "unchecked_size: %#08x\n", c->unchecked_size);
0476     printk(JFFS2_DBG "free_size: %#08x\n",      c->free_size);
0477     printk(JFFS2_DBG "erasing_size: %#08x\n",   c->erasing_size);
0478     printk(JFFS2_DBG "bad_size: %#08x\n",       c->bad_size);
0479     printk(JFFS2_DBG "sector_size: %#08x\n",    c->sector_size);
0480     printk(JFFS2_DBG "jffs2_reserved_blocks size: %#08x\n",
0481                 c->sector_size * c->resv_blocks_write);
0482 
0483     if (c->nextblock)
0484         printk(JFFS2_DBG "nextblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
0485             c->nextblock->offset, c->nextblock->used_size,
0486             c->nextblock->dirty_size, c->nextblock->wasted_size,
0487             c->nextblock->unchecked_size, c->nextblock->free_size);
0488     else
0489         printk(JFFS2_DBG "nextblock: NULL\n");
0490 
0491     if (c->gcblock)
0492         printk(JFFS2_DBG "gcblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
0493             c->gcblock->offset, c->gcblock->used_size, c->gcblock->dirty_size,
0494             c->gcblock->wasted_size, c->gcblock->unchecked_size, c->gcblock->free_size);
0495     else
0496         printk(JFFS2_DBG "gcblock: NULL\n");
0497 
0498     if (list_empty(&c->clean_list)) {
0499         printk(JFFS2_DBG "clean_list: empty\n");
0500     } else {
0501         struct list_head *this;
0502         int numblocks = 0;
0503         uint32_t dirty = 0;
0504 
0505         list_for_each(this, &c->clean_list) {
0506             struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
0507             numblocks ++;
0508             dirty += jeb->wasted_size;
0509             if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
0510                 printk(JFFS2_DBG "clean_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
0511                     jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
0512                     jeb->unchecked_size, jeb->free_size);
0513             }
0514         }
0515 
0516         printk (JFFS2_DBG "Contains %d blocks with total wasted size %u, average wasted size: %u\n",
0517             numblocks, dirty, dirty / numblocks);
0518     }
0519 
0520     if (list_empty(&c->very_dirty_list)) {
0521         printk(JFFS2_DBG "very_dirty_list: empty\n");
0522     } else {
0523         struct list_head *this;
0524         int numblocks = 0;
0525         uint32_t dirty = 0;
0526 
0527         list_for_each(this, &c->very_dirty_list) {
0528             struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
0529 
0530             numblocks ++;
0531             dirty += jeb->dirty_size;
0532             if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
0533                 printk(JFFS2_DBG "very_dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
0534                     jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
0535                     jeb->unchecked_size, jeb->free_size);
0536             }
0537         }
0538 
0539         printk (JFFS2_DBG "Contains %d blocks with total dirty size %u, average dirty size: %u\n",
0540             numblocks, dirty, dirty / numblocks);
0541     }
0542 
0543     if (list_empty(&c->dirty_list)) {
0544         printk(JFFS2_DBG "dirty_list: empty\n");
0545     } else {
0546         struct list_head *this;
0547         int numblocks = 0;
0548         uint32_t dirty = 0;
0549 
0550         list_for_each(this, &c->dirty_list) {
0551             struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
0552 
0553             numblocks ++;
0554             dirty += jeb->dirty_size;
0555             if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
0556                 printk(JFFS2_DBG "dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
0557                     jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
0558                     jeb->unchecked_size, jeb->free_size);
0559             }
0560         }
0561 
0562         printk (JFFS2_DBG "contains %d blocks with total dirty size %u, average dirty size: %u\n",
0563             numblocks, dirty, dirty / numblocks);
0564     }
0565 
0566     if (list_empty(&c->erasable_list)) {
0567         printk(JFFS2_DBG "erasable_list: empty\n");
0568     } else {
0569         struct list_head *this;
0570 
0571         list_for_each(this, &c->erasable_list) {
0572             struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
0573 
0574             if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
0575                 printk(JFFS2_DBG "erasable_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
0576                     jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
0577                     jeb->unchecked_size, jeb->free_size);
0578             }
0579         }
0580     }
0581 
0582     if (list_empty(&c->erasing_list)) {
0583         printk(JFFS2_DBG "erasing_list: empty\n");
0584     } else {
0585         struct list_head *this;
0586 
0587         list_for_each(this, &c->erasing_list) {
0588             struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
0589 
0590             if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
0591                 printk(JFFS2_DBG "erasing_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
0592                     jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
0593                     jeb->unchecked_size, jeb->free_size);
0594             }
0595         }
0596     }
0597     if (list_empty(&c->erase_checking_list)) {
0598         printk(JFFS2_DBG "erase_checking_list: empty\n");
0599     } else {
0600         struct list_head *this;
0601 
0602         list_for_each(this, &c->erase_checking_list) {
0603             struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
0604 
0605             if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
0606                 printk(JFFS2_DBG "erase_checking_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
0607                     jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
0608                     jeb->unchecked_size, jeb->free_size);
0609             }
0610         }
0611     }
0612 
0613     if (list_empty(&c->erase_pending_list)) {
0614         printk(JFFS2_DBG "erase_pending_list: empty\n");
0615     } else {
0616         struct list_head *this;
0617 
0618         list_for_each(this, &c->erase_pending_list) {
0619             struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
0620 
0621             if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
0622                 printk(JFFS2_DBG "erase_pending_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
0623                     jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
0624                     jeb->unchecked_size, jeb->free_size);
0625             }
0626         }
0627     }
0628 
0629     if (list_empty(&c->erasable_pending_wbuf_list)) {
0630         printk(JFFS2_DBG "erasable_pending_wbuf_list: empty\n");
0631     } else {
0632         struct list_head *this;
0633 
0634         list_for_each(this, &c->erasable_pending_wbuf_list) {
0635             struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
0636 
0637             if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
0638                 printk(JFFS2_DBG "erasable_pending_wbuf_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
0639                     jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
0640                     jeb->unchecked_size, jeb->free_size);
0641             }
0642         }
0643     }
0644 
0645     if (list_empty(&c->free_list)) {
0646         printk(JFFS2_DBG "free_list: empty\n");
0647     } else {
0648         struct list_head *this;
0649 
0650         list_for_each(this, &c->free_list) {
0651             struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
0652 
0653             if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
0654                 printk(JFFS2_DBG "free_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
0655                     jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
0656                     jeb->unchecked_size, jeb->free_size);
0657             }
0658         }
0659     }
0660 
0661     if (list_empty(&c->bad_list)) {
0662         printk(JFFS2_DBG "bad_list: empty\n");
0663     } else {
0664         struct list_head *this;
0665 
0666         list_for_each(this, &c->bad_list) {
0667             struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
0668 
0669             if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
0670                 printk(JFFS2_DBG "bad_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
0671                     jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
0672                     jeb->unchecked_size, jeb->free_size);
0673             }
0674         }
0675     }
0676 
0677     if (list_empty(&c->bad_used_list)) {
0678         printk(JFFS2_DBG "bad_used_list: empty\n");
0679     } else {
0680         struct list_head *this;
0681 
0682         list_for_each(this, &c->bad_used_list) {
0683             struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
0684 
0685             if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
0686                 printk(JFFS2_DBG "bad_used_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
0687                     jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
0688                     jeb->unchecked_size, jeb->free_size);
0689             }
0690         }
0691     }
0692 }
0693 
0694 void
0695 __jffs2_dbg_dump_fragtree(struct jffs2_inode_info *f)
0696 {
0697     mutex_lock(&f->sem);
0698     jffs2_dbg_dump_fragtree_nolock(f);
0699     mutex_unlock(&f->sem);
0700 }
0701 
0702 void
0703 __jffs2_dbg_dump_fragtree_nolock(struct jffs2_inode_info *f)
0704 {
0705     struct jffs2_node_frag *this = frag_first(&f->fragtree);
0706     uint32_t lastofs = 0;
0707     int buggy = 0;
0708 
0709     printk(JFFS2_DBG_MSG_PREFIX " dump fragtree of ino #%u\n", f->inocache->ino);
0710     while(this) {
0711         if (this->node)
0712             printk(JFFS2_DBG "frag %#04x-%#04x: %#08x(%d) on flash (*%p), left (%p), right (%p), parent (%p)\n",
0713                 this->ofs, this->ofs+this->size, ref_offset(this->node->raw),
0714                 ref_flags(this->node->raw), this, frag_left(this), frag_right(this),
0715                 frag_parent(this));
0716         else
0717             printk(JFFS2_DBG "frag %#04x-%#04x: hole (*%p). left (%p), right (%p), parent (%p)\n",
0718                 this->ofs, this->ofs+this->size, this, frag_left(this),
0719                 frag_right(this), frag_parent(this));
0720         if (this->ofs != lastofs)
0721             buggy = 1;
0722         lastofs = this->ofs + this->size;
0723         this = frag_next(this);
0724     }
0725 
0726     if (f->metadata)
0727         printk(JFFS2_DBG "metadata at 0x%08x\n", ref_offset(f->metadata->raw));
0728 
0729     if (buggy) {
0730         JFFS2_ERROR("frag tree got a hole in it.\n");
0731         BUG();
0732     }
0733 }
0734 
0735 #define JFFS2_BUFDUMP_BYTES_PER_LINE    32
0736 void
0737 __jffs2_dbg_dump_buffer(unsigned char *buf, int len, uint32_t offs)
0738 {
0739     int skip;
0740     int i;
0741 
0742     printk(JFFS2_DBG_MSG_PREFIX " dump from offset %#08x to offset %#08x (%x bytes).\n",
0743         offs, offs + len, len);
0744     i = skip = offs % JFFS2_BUFDUMP_BYTES_PER_LINE;
0745     offs = offs & ~(JFFS2_BUFDUMP_BYTES_PER_LINE - 1);
0746 
0747     if (skip != 0)
0748         printk(JFFS2_DBG "%#08x: ", offs);
0749 
0750     while (skip--)
0751         printk("   ");
0752 
0753     while (i < len) {
0754         if ((i % JFFS2_BUFDUMP_BYTES_PER_LINE) == 0 && i != len -1) {
0755             if (i != 0)
0756                 printk("\n");
0757             offs += JFFS2_BUFDUMP_BYTES_PER_LINE;
0758             printk(JFFS2_DBG "%0#8x: ", offs);
0759         }
0760 
0761         printk("%02x ", buf[i]);
0762 
0763         i += 1;
0764     }
0765 
0766     printk("\n");
0767 }
0768 
0769 /*
0770  * Dump a JFFS2 node.
0771  */
0772 void
0773 __jffs2_dbg_dump_node(struct jffs2_sb_info *c, uint32_t ofs)
0774 {
0775     union jffs2_node_union node;
0776     int len = sizeof(union jffs2_node_union);
0777     size_t retlen;
0778     uint32_t crc;
0779     int ret;
0780 
0781     printk(JFFS2_DBG_MSG_PREFIX " dump node at offset %#08x.\n", ofs);
0782 
0783     ret = jffs2_flash_read(c, ofs, len, &retlen, (unsigned char *)&node);
0784     if (ret || (retlen != len)) {
0785         JFFS2_ERROR("read %d bytes failed or short. ret %d, retlen %zd.\n",
0786             len, ret, retlen);
0787         return;
0788     }
0789 
0790     printk(JFFS2_DBG "magic:\t%#04x\n", je16_to_cpu(node.u.magic));
0791     printk(JFFS2_DBG "nodetype:\t%#04x\n", je16_to_cpu(node.u.nodetype));
0792     printk(JFFS2_DBG "totlen:\t%#08x\n", je32_to_cpu(node.u.totlen));
0793     printk(JFFS2_DBG "hdr_crc:\t%#08x\n", je32_to_cpu(node.u.hdr_crc));
0794 
0795     crc = crc32(0, &node.u, sizeof(node.u) - 4);
0796     if (crc != je32_to_cpu(node.u.hdr_crc)) {
0797         JFFS2_ERROR("wrong common header CRC.\n");
0798         return;
0799     }
0800 
0801     if (je16_to_cpu(node.u.magic) != JFFS2_MAGIC_BITMASK &&
0802         je16_to_cpu(node.u.magic) != JFFS2_OLD_MAGIC_BITMASK)
0803     {
0804         JFFS2_ERROR("wrong node magic: %#04x instead of %#04x.\n",
0805             je16_to_cpu(node.u.magic), JFFS2_MAGIC_BITMASK);
0806         return;
0807     }
0808 
0809     switch(je16_to_cpu(node.u.nodetype)) {
0810 
0811     case JFFS2_NODETYPE_INODE:
0812 
0813         printk(JFFS2_DBG "the node is inode node\n");
0814         printk(JFFS2_DBG "ino:\t%#08x\n", je32_to_cpu(node.i.ino));
0815         printk(JFFS2_DBG "version:\t%#08x\n", je32_to_cpu(node.i.version));
0816         printk(JFFS2_DBG "mode:\t%#08x\n", node.i.mode.m);
0817         printk(JFFS2_DBG "uid:\t%#04x\n", je16_to_cpu(node.i.uid));
0818         printk(JFFS2_DBG "gid:\t%#04x\n", je16_to_cpu(node.i.gid));
0819         printk(JFFS2_DBG "isize:\t%#08x\n", je32_to_cpu(node.i.isize));
0820         printk(JFFS2_DBG "atime:\t%#08x\n", je32_to_cpu(node.i.atime));
0821         printk(JFFS2_DBG "mtime:\t%#08x\n", je32_to_cpu(node.i.mtime));
0822         printk(JFFS2_DBG "ctime:\t%#08x\n", je32_to_cpu(node.i.ctime));
0823         printk(JFFS2_DBG "offset:\t%#08x\n", je32_to_cpu(node.i.offset));
0824         printk(JFFS2_DBG "csize:\t%#08x\n", je32_to_cpu(node.i.csize));
0825         printk(JFFS2_DBG "dsize:\t%#08x\n", je32_to_cpu(node.i.dsize));
0826         printk(JFFS2_DBG "compr:\t%#02x\n", node.i.compr);
0827         printk(JFFS2_DBG "usercompr:\t%#02x\n", node.i.usercompr);
0828         printk(JFFS2_DBG "flags:\t%#04x\n", je16_to_cpu(node.i.flags));
0829         printk(JFFS2_DBG "data_crc:\t%#08x\n", je32_to_cpu(node.i.data_crc));
0830         printk(JFFS2_DBG "node_crc:\t%#08x\n", je32_to_cpu(node.i.node_crc));
0831 
0832         crc = crc32(0, &node.i, sizeof(node.i) - 8);
0833         if (crc != je32_to_cpu(node.i.node_crc)) {
0834             JFFS2_ERROR("wrong node header CRC.\n");
0835             return;
0836         }
0837         break;
0838 
0839     case JFFS2_NODETYPE_DIRENT:
0840 
0841         printk(JFFS2_DBG "the node is dirent node\n");
0842         printk(JFFS2_DBG "pino:\t%#08x\n", je32_to_cpu(node.d.pino));
0843         printk(JFFS2_DBG "version:\t%#08x\n", je32_to_cpu(node.d.version));
0844         printk(JFFS2_DBG "ino:\t%#08x\n", je32_to_cpu(node.d.ino));
0845         printk(JFFS2_DBG "mctime:\t%#08x\n", je32_to_cpu(node.d.mctime));
0846         printk(JFFS2_DBG "nsize:\t%#02x\n", node.d.nsize);
0847         printk(JFFS2_DBG "type:\t%#02x\n", node.d.type);
0848         printk(JFFS2_DBG "node_crc:\t%#08x\n", je32_to_cpu(node.d.node_crc));
0849         printk(JFFS2_DBG "name_crc:\t%#08x\n", je32_to_cpu(node.d.name_crc));
0850 
0851         node.d.name[node.d.nsize] = '\0';
0852         printk(JFFS2_DBG "name:\t\"%s\"\n", node.d.name);
0853 
0854         crc = crc32(0, &node.d, sizeof(node.d) - 8);
0855         if (crc != je32_to_cpu(node.d.node_crc)) {
0856             JFFS2_ERROR("wrong node header CRC.\n");
0857             return;
0858         }
0859         break;
0860 
0861     default:
0862         printk(JFFS2_DBG "node type is unknown\n");
0863         break;
0864     }
0865 }
0866 #endif /* JFFS2_DBG_DUMPS || JFFS2_DBG_PARANOIA_CHECKS */