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