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