source: rtems/cpukit/libfs/src/jffs2/src/debug.c @ 78b85286

4.115
Last change on this file since 78b85286 was 0c0f128, checked in by Sebastian Huber <sebastian.huber@…>, on 09/12/13 at 13:57:47

JFFS2: Import from Linux

Import of Journalling Flash File System, Version 2 from Linux 3.11.
This part of the Linux kernel is under a separate license which is
similar to the RTEMS license.

The file "cpukit/libfs/src/jffs2/include/linux/jffs2.h" is a copy of
"linux-3.11/include/uapi/linux/jffs2.h".

The file "LICENSE.JFFS2" is a copy of "linux-3.11/fs/jffs2/LICENCE".

The files

"linux-3.11/fs/jffs2/LICENCE",
"linux-3.11/fs/jffs2/acl.h",
"linux-3.11/fs/jffs2/build.c",
"linux-3.11/fs/jffs2/compr.c",
"linux-3.11/fs/jffs2/compr.h",
"linux-3.11/fs/jffs2/compr_rtime.c",
"linux-3.11/fs/jffs2/compr_rubin.c",
"linux-3.11/fs/jffs2/compr_zlib.c",
"linux-3.11/fs/jffs2/debug.c",
"linux-3.11/fs/jffs2/debug.h",
"linux-3.11/fs/jffs2/erase.c",
"linux-3.11/fs/jffs2/gc.c",
"linux-3.11/fs/jffs2/jffs2_fs_i.h",
"linux-3.11/fs/jffs2/jffs2_fs_sb.h",
"linux-3.11/fs/jffs2/nodelist.c",
"linux-3.11/fs/jffs2/nodelist.h",
"linux-3.11/fs/jffs2/nodemgmt.c",
"linux-3.11/fs/jffs2/read.c",
"linux-3.11/fs/jffs2/readinode.c",
"linux-3.11/fs/jffs2/scan.c",
"linux-3.11/fs/jffs2/summary.h",
"linux-3.11/fs/jffs2/write.c", and
"linux-3.11/fs/jffs2/xattr.h"

are copied to "cpukit/libfs/src/jffs2/src".

  • Property mode set to 100644
File size: 25.7 KB
Line 
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 */
Note: See TracBrowser for help on using the repository browser.