blob: 3a32c64ed4975260079e7b9f3c435eecef18b534 [file] [log] [blame]
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +01001/*
2 * JFFS2 -- Journalling Flash File System, Version 2.
3 *
David Woodhousec00c3102007-04-25 14:16:47 +01004 * Copyright © 2001-2007 Red Hat, Inc.
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +01005 *
6 * Created by David Woodhouse <dwmw2@infradead.org>
7 *
8 * For licensing information, see the file 'LICENCE' in this directory.
9 *
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +010010 */
David Woodhousec00c3102007-04-25 14:16:47 +010011
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +010012#include <linux/kernel.h>
Andrew Lunn737b7662005-07-30 16:29:30 +010013#include <linux/types.h>
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +010014#include <linux/pagemap.h>
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +010015#include <linux/crc32.h>
16#include <linux/jffs2.h>
Artem B. Bityutskiy733802d2005-09-22 12:25:00 +010017#include <linux/mtd/mtd.h>
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +010018#include "nodelist.h"
19#include "debug.h"
20
Artem B. Bityutskiy45ca1b52005-08-05 12:43:47 +010021#ifdef JFFS2_DBG_SANITY_CHECKS
22
23void
24__jffs2_dbg_acct_sanity_check_nolock(struct jffs2_sb_info *c,
25 struct jffs2_eraseblock *jeb)
26{
27 if (unlikely(jeb && jeb->used_size + jeb->dirty_size +
28 jeb->free_size + jeb->wasted_size +
29 jeb->unchecked_size != c->sector_size)) {
30 JFFS2_ERROR("eeep, space accounting for block at 0x%08x is screwed.\n", jeb->offset);
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +010031 JFFS2_ERROR("free %#08x + dirty %#08x + used %#08x + wasted %#08x + unchecked %#08x != total %#08x.\n",
32 jeb->free_size, jeb->dirty_size, jeb->used_size,
Artem B. Bityutskiy45ca1b52005-08-05 12:43:47 +010033 jeb->wasted_size, jeb->unchecked_size, c->sector_size);
34 BUG();
35 }
36
37 if (unlikely(c->used_size + c->dirty_size + c->free_size + c->erasing_size + c->bad_size
38 + c->wasted_size + c->unchecked_size != c->flash_size)) {
39 JFFS2_ERROR("eeep, space accounting superblock info is screwed.\n");
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +010040 JFFS2_ERROR("free %#08x + dirty %#08x + used %#08x + erasing %#08x + bad %#08x + wasted %#08x + unchecked %#08x != total %#08x.\n",
Artem B. Bityutskiy45ca1b52005-08-05 12:43:47 +010041 c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size,
42 c->wasted_size, c->unchecked_size, c->flash_size);
43 BUG();
44 }
45}
46
47void
48__jffs2_dbg_acct_sanity_check(struct jffs2_sb_info *c,
49 struct jffs2_eraseblock *jeb)
50{
51 spin_lock(&c->erase_completion_lock);
52 jffs2_dbg_acct_sanity_check_nolock(c, jeb);
53 spin_unlock(&c->erase_completion_lock);
54}
55
56#endif /* JFFS2_DBG_SANITY_CHECKS */
57
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +010058#ifdef JFFS2_DBG_PARANOIA_CHECKS
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +010059/*
60 * Check the fragtree.
61 */
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +010062void
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +010063__jffs2_dbg_fragtree_paranoia_check(struct jffs2_inode_info *f)
64{
65 down(&f->sem);
66 __jffs2_dbg_fragtree_paranoia_check_nolock(f);
67 up(&f->sem);
68}
Thomas Gleixner182ec4e2005-11-07 11:16:07 +000069
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +010070void
71__jffs2_dbg_fragtree_paranoia_check_nolock(struct jffs2_inode_info *f)
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +010072{
73 struct jffs2_node_frag *frag;
74 int bitched = 0;
75
76 for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) {
77 struct jffs2_full_dnode *fn = frag->node;
78
79 if (!fn || !fn->raw)
80 continue;
81
82 if (ref_flags(fn->raw) == REF_PRISTINE) {
83 if (fn->frags > 1) {
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +010084 JFFS2_ERROR("REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2.\n",
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +010085 ref_offset(fn->raw), fn->frags);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +010086 bitched = 1;
87 }
88
89 /* A hole node which isn't multi-page should be garbage-collected
90 and merged anyway, so we just check for the frag size here,
91 rather than mucking around with actually reading the node
92 and checking the compression type, which is the real way
93 to tell a hole node. */
94 if (frag->ofs & (PAGE_CACHE_SIZE-1) && frag_prev(frag)
95 && frag_prev(frag)->size < PAGE_CACHE_SIZE && frag_prev(frag)->node) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +010096 JFFS2_ERROR("REF_PRISTINE node at 0x%08x had a previous non-hole frag in the same page. Tell dwmw2.\n",
97 ref_offset(fn->raw));
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +010098 bitched = 1;
99 }
100
101 if ((frag->ofs+frag->size) & (PAGE_CACHE_SIZE-1) && frag_next(frag)
102 && frag_next(frag)->size < PAGE_CACHE_SIZE && frag_next(frag)->node) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100103 JFFS2_ERROR("REF_PRISTINE node at 0x%08x (%08x-%08x) had a following non-hole frag in the same page. Tell dwmw2.\n",
104 ref_offset(fn->raw), frag->ofs, frag->ofs+frag->size);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100105 bitched = 1;
106 }
107 }
108 }
109
110 if (bitched) {
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100111 JFFS2_ERROR("fragtree is corrupted.\n");
112 __jffs2_dbg_dump_fragtree_nolock(f);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100113 BUG();
114 }
115}
116
117/*
118 * Check if the flash contains all 0xFF before we start writing.
119 */
120void
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100121__jffs2_dbg_prewrite_paranoia_check(struct jffs2_sb_info *c,
122 uint32_t ofs, int len)
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100123{
124 size_t retlen;
125 int ret, i;
126 unsigned char *buf;
127
128 buf = kmalloc(len, GFP_KERNEL);
129 if (!buf)
130 return;
131
132 ret = jffs2_flash_read(c, ofs, len, &retlen, buf);
133 if (ret || (retlen != len)) {
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100134 JFFS2_WARNING("read %d bytes failed or short. ret %d, retlen %zd.\n",
135 len, ret, retlen);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100136 kfree(buf);
137 return;
138 }
139
140 ret = 0;
141 for (i = 0; i < len; i++)
142 if (buf[i] != 0xff)
143 ret = 1;
144
145 if (ret) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100146 JFFS2_ERROR("argh, about to write node to %#08x on flash, but there are data already there. The first corrupted byte is at %#08x offset.\n",
147 ofs, ofs + i);
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100148 __jffs2_dbg_dump_buffer(buf, len, ofs);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100149 kfree(buf);
150 BUG();
151 }
152
153 kfree(buf);
154}
155
156/*
157 * Check the space accounting and node_ref list correctness for the JFFS2 erasable block 'jeb'.
158 */
159void
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100160__jffs2_dbg_acct_paranoia_check(struct jffs2_sb_info *c,
161 struct jffs2_eraseblock *jeb)
162{
163 spin_lock(&c->erase_completion_lock);
164 __jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
165 spin_unlock(&c->erase_completion_lock);
166}
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000167
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100168void
169__jffs2_dbg_acct_paranoia_check_nolock(struct jffs2_sb_info *c,
170 struct jffs2_eraseblock *jeb)
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100171{
172 uint32_t my_used_size = 0;
173 uint32_t my_unchecked_size = 0;
174 uint32_t my_dirty_size = 0;
175 struct jffs2_raw_node_ref *ref2 = jeb->first_node;
176
177 while (ref2) {
178 uint32_t totlen = ref_totlen(c, jeb, ref2);
179
Kyungmin Parkabb536e2006-12-22 16:39:30 +0900180 if (ref_offset(ref2) < jeb->offset ||
181 ref_offset(ref2) > jeb->offset + c->sector_size) {
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100182 JFFS2_ERROR("node_ref %#08x shouldn't be in block at %#08x.\n",
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100183 ref_offset(ref2), jeb->offset);
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100184 goto error;
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100185
186 }
187 if (ref_flags(ref2) == REF_UNCHECKED)
188 my_unchecked_size += totlen;
189 else if (!ref_obsolete(ref2))
190 my_used_size += totlen;
191 else
192 my_dirty_size += totlen;
193
David Woodhouse99988f72006-05-24 09:04:17 +0100194 if ((!ref_next(ref2)) != (ref2 == jeb->last_node)) {
195 JFFS2_ERROR("node_ref for node at %#08x (mem %p) has next at %#08x (mem %p), last_node is at %#08x (mem %p).\n",
196 ref_offset(ref2), ref2, ref_offset(ref_next(ref2)), ref_next(ref2),
197 ref_offset(jeb->last_node), jeb->last_node);
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100198 goto error;
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100199 }
David Woodhouse99988f72006-05-24 09:04:17 +0100200 ref2 = ref_next(ref2);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100201 }
202
203 if (my_used_size != jeb->used_size) {
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100204 JFFS2_ERROR("Calculated used size %#08x != stored used size %#08x.\n",
205 my_used_size, jeb->used_size);
206 goto error;
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100207 }
208
209 if (my_unchecked_size != jeb->unchecked_size) {
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100210 JFFS2_ERROR("Calculated unchecked size %#08x != stored unchecked size %#08x.\n",
211 my_unchecked_size, jeb->unchecked_size);
212 goto error;
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100213 }
214
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100215#if 0
216 /* This should work when we implement ref->__totlen elemination */
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100217 if (my_dirty_size != jeb->dirty_size + jeb->wasted_size) {
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100218 JFFS2_ERROR("Calculated dirty+wasted size %#08x != stored dirty + wasted size %#08x\n",
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100219 my_dirty_size, jeb->dirty_size + jeb->wasted_size);
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100220 goto error;
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100221 }
222
223 if (jeb->free_size == 0
224 && my_used_size + my_unchecked_size + my_dirty_size != c->sector_size) {
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100225 JFFS2_ERROR("The sum of all nodes in block (%#x) != size of block (%#x)\n",
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100226 my_used_size + my_unchecked_size + my_dirty_size,
227 c->sector_size);
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100228 goto error;
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100229 }
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100230#endif
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100231
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100232 return;
233
234error:
235 __jffs2_dbg_dump_node_refs_nolock(c, jeb);
236 __jffs2_dbg_dump_jeb_nolock(jeb);
237 __jffs2_dbg_dump_block_lists_nolock(c);
238 BUG();
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000239
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100240}
241#endif /* JFFS2_DBG_PARANOIA_CHECKS */
242
243#if defined(JFFS2_DBG_DUMPS) || defined(JFFS2_DBG_PARANOIA_CHECKS)
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100244/*
245 * Dump the node_refs of the 'jeb' JFFS2 eraseblock.
246 */
247void
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100248__jffs2_dbg_dump_node_refs(struct jffs2_sb_info *c,
249 struct jffs2_eraseblock *jeb)
250{
251 spin_lock(&c->erase_completion_lock);
252 __jffs2_dbg_dump_node_refs_nolock(c, jeb);
253 spin_unlock(&c->erase_completion_lock);
254}
255
256void
257__jffs2_dbg_dump_node_refs_nolock(struct jffs2_sb_info *c,
258 struct jffs2_eraseblock *jeb)
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100259{
260 struct jffs2_raw_node_ref *ref;
261 int i = 0;
262
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100263 printk(JFFS2_DBG_MSG_PREFIX " Dump node_refs of the eraseblock %#08x\n", jeb->offset);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100264 if (!jeb->first_node) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100265 printk(JFFS2_DBG_MSG_PREFIX " no nodes in the eraseblock %#08x\n", jeb->offset);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100266 return;
267 }
268
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100269 printk(JFFS2_DBG);
David Woodhouse99988f72006-05-24 09:04:17 +0100270 for (ref = jeb->first_node; ; ref = ref_next(ref)) {
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100271 printk("%#08x(%#x)", ref_offset(ref), ref->__totlen);
David Woodhouse99988f72006-05-24 09:04:17 +0100272 if (ref_next(ref))
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100273 printk("->");
274 else
275 break;
276 if (++i == 4) {
277 i = 0;
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100278 printk("\n" JFFS2_DBG);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100279 }
280 }
281 printk("\n");
282}
283
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100284/*
285 * Dump an eraseblock's space accounting.
286 */
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100287void
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100288__jffs2_dbg_dump_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100289{
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100290 spin_lock(&c->erase_completion_lock);
291 __jffs2_dbg_dump_jeb_nolock(jeb);
292 spin_unlock(&c->erase_completion_lock);
293}
294
295void
296__jffs2_dbg_dump_jeb_nolock(struct jffs2_eraseblock *jeb)
297{
298 if (!jeb)
299 return;
300
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100301 printk(JFFS2_DBG_MSG_PREFIX " dump space accounting for the eraseblock at %#08x:\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100302 jeb->offset);
303
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100304 printk(JFFS2_DBG "used_size: %#08x\n", jeb->used_size);
305 printk(JFFS2_DBG "dirty_size: %#08x\n", jeb->dirty_size);
306 printk(JFFS2_DBG "wasted_size: %#08x\n", jeb->wasted_size);
307 printk(JFFS2_DBG "unchecked_size: %#08x\n", jeb->unchecked_size);
308 printk(JFFS2_DBG "free_size: %#08x\n", jeb->free_size);
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100309}
310
311void
312__jffs2_dbg_dump_block_lists(struct jffs2_sb_info *c)
313{
314 spin_lock(&c->erase_completion_lock);
315 __jffs2_dbg_dump_block_lists_nolock(c);
316 spin_unlock(&c->erase_completion_lock);
317}
318
319void
320__jffs2_dbg_dump_block_lists_nolock(struct jffs2_sb_info *c)
321{
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100322 printk(JFFS2_DBG_MSG_PREFIX " dump JFFS2 blocks lists:\n");
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000323
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100324 printk(JFFS2_DBG "flash_size: %#08x\n", c->flash_size);
325 printk(JFFS2_DBG "used_size: %#08x\n", c->used_size);
326 printk(JFFS2_DBG "dirty_size: %#08x\n", c->dirty_size);
327 printk(JFFS2_DBG "wasted_size: %#08x\n", c->wasted_size);
328 printk(JFFS2_DBG "unchecked_size: %#08x\n", c->unchecked_size);
329 printk(JFFS2_DBG "free_size: %#08x\n", c->free_size);
330 printk(JFFS2_DBG "erasing_size: %#08x\n", c->erasing_size);
331 printk(JFFS2_DBG "bad_size: %#08x\n", c->bad_size);
332 printk(JFFS2_DBG "sector_size: %#08x\n", c->sector_size);
333 printk(JFFS2_DBG "jffs2_reserved_blocks size: %#08x\n",
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100334 c->sector_size * c->resv_blocks_write);
335
336 if (c->nextblock)
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100337 printk(JFFS2_DBG "nextblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100338 c->nextblock->offset, c->nextblock->used_size,
339 c->nextblock->dirty_size, c->nextblock->wasted_size,
340 c->nextblock->unchecked_size, c->nextblock->free_size);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100341 else
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100342 printk(JFFS2_DBG "nextblock: NULL\n");
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100343
344 if (c->gcblock)
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100345 printk(JFFS2_DBG "gcblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100346 c->gcblock->offset, c->gcblock->used_size, c->gcblock->dirty_size,
347 c->gcblock->wasted_size, c->gcblock->unchecked_size, c->gcblock->free_size);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100348 else
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100349 printk(JFFS2_DBG "gcblock: NULL\n");
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100350
351 if (list_empty(&c->clean_list)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100352 printk(JFFS2_DBG "clean_list: empty\n");
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100353 } else {
354 struct list_head *this;
355 int numblocks = 0;
356 uint32_t dirty = 0;
357
358 list_for_each(this, &c->clean_list) {
359 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
360 numblocks ++;
361 dirty += jeb->wasted_size;
362 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100363 printk(JFFS2_DBG "clean_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100364 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
365 jeb->unchecked_size, jeb->free_size);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100366 }
367 }
368
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100369 printk (JFFS2_DBG "Contains %d blocks with total wasted size %u, average wasted size: %u\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100370 numblocks, dirty, dirty / numblocks);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100371 }
372
373 if (list_empty(&c->very_dirty_list)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100374 printk(JFFS2_DBG "very_dirty_list: empty\n");
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100375 } else {
376 struct list_head *this;
377 int numblocks = 0;
378 uint32_t dirty = 0;
379
380 list_for_each(this, &c->very_dirty_list) {
381 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
382
383 numblocks ++;
384 dirty += jeb->dirty_size;
385 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100386 printk(JFFS2_DBG "very_dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100387 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
388 jeb->unchecked_size, jeb->free_size);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100389 }
390 }
391
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100392 printk (JFFS2_DBG "Contains %d blocks with total dirty size %u, average dirty size: %u\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100393 numblocks, dirty, dirty / numblocks);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100394 }
395
396 if (list_empty(&c->dirty_list)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100397 printk(JFFS2_DBG "dirty_list: empty\n");
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100398 } else {
399 struct list_head *this;
400 int numblocks = 0;
401 uint32_t dirty = 0;
402
403 list_for_each(this, &c->dirty_list) {
404 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
405
406 numblocks ++;
407 dirty += jeb->dirty_size;
408 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100409 printk(JFFS2_DBG "dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100410 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
411 jeb->unchecked_size, jeb->free_size);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100412 }
413 }
414
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100415 printk (JFFS2_DBG "contains %d blocks with total dirty size %u, average dirty size: %u\n",
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100416 numblocks, dirty, dirty / numblocks);
417 }
418
419 if (list_empty(&c->erasable_list)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100420 printk(JFFS2_DBG "erasable_list: empty\n");
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100421 } else {
422 struct list_head *this;
423
424 list_for_each(this, &c->erasable_list) {
425 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
426
427 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100428 printk(JFFS2_DBG "erasable_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100429 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
430 jeb->unchecked_size, jeb->free_size);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100431 }
432 }
433 }
434
435 if (list_empty(&c->erasing_list)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100436 printk(JFFS2_DBG "erasing_list: empty\n");
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100437 } else {
438 struct list_head *this;
439
440 list_for_each(this, &c->erasing_list) {
441 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
442
443 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100444 printk(JFFS2_DBG "erasing_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100445 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
446 jeb->unchecked_size, jeb->free_size);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100447 }
448 }
449 }
450
451 if (list_empty(&c->erase_pending_list)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100452 printk(JFFS2_DBG "erase_pending_list: empty\n");
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100453 } else {
454 struct list_head *this;
455
456 list_for_each(this, &c->erase_pending_list) {
457 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
458
459 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100460 printk(JFFS2_DBG "erase_pending_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100461 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
462 jeb->unchecked_size, jeb->free_size);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100463 }
464 }
465 }
466
467 if (list_empty(&c->erasable_pending_wbuf_list)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100468 printk(JFFS2_DBG "erasable_pending_wbuf_list: empty\n");
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100469 } else {
470 struct list_head *this;
471
472 list_for_each(this, &c->erasable_pending_wbuf_list) {
473 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
474
475 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100476 printk(JFFS2_DBG "erasable_pending_wbuf_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100477 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
478 jeb->unchecked_size, jeb->free_size);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100479 }
480 }
481 }
482
483 if (list_empty(&c->free_list)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100484 printk(JFFS2_DBG "free_list: empty\n");
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100485 } else {
486 struct list_head *this;
487
488 list_for_each(this, &c->free_list) {
489 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
490
491 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100492 printk(JFFS2_DBG "free_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100493 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
494 jeb->unchecked_size, jeb->free_size);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100495 }
496 }
497 }
498
499 if (list_empty(&c->bad_list)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100500 printk(JFFS2_DBG "bad_list: empty\n");
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100501 } else {
502 struct list_head *this;
503
504 list_for_each(this, &c->bad_list) {
505 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
506
507 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100508 printk(JFFS2_DBG "bad_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100509 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
510 jeb->unchecked_size, jeb->free_size);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100511 }
512 }
513 }
514
515 if (list_empty(&c->bad_used_list)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100516 printk(JFFS2_DBG "bad_used_list: empty\n");
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100517 } else {
518 struct list_head *this;
519
520 list_for_each(this, &c->bad_used_list) {
521 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
522
523 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100524 printk(JFFS2_DBG "bad_used_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100525 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
526 jeb->unchecked_size, jeb->free_size);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100527 }
528 }
529 }
530}
531
532void
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100533__jffs2_dbg_dump_fragtree(struct jffs2_inode_info *f)
534{
535 down(&f->sem);
536 jffs2_dbg_dump_fragtree_nolock(f);
537 up(&f->sem);
538}
539
540void
541__jffs2_dbg_dump_fragtree_nolock(struct jffs2_inode_info *f)
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100542{
543 struct jffs2_node_frag *this = frag_first(&f->fragtree);
544 uint32_t lastofs = 0;
545 int buggy = 0;
546
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100547 printk(JFFS2_DBG_MSG_PREFIX " dump fragtree of ino #%u\n", f->inocache->ino);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100548 while(this) {
549 if (this->node)
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100550 printk(JFFS2_DBG "frag %#04x-%#04x: %#08x(%d) on flash (*%p), left (%p), right (%p), parent (%p)\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100551 this->ofs, this->ofs+this->size, ref_offset(this->node->raw),
552 ref_flags(this->node->raw), this, frag_left(this), frag_right(this),
553 frag_parent(this));
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100554 else
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100555 printk(JFFS2_DBG "frag %#04x-%#04x: hole (*%p). left (%p), right (%p), parent (%p)\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100556 this->ofs, this->ofs+this->size, this, frag_left(this),
557 frag_right(this), frag_parent(this));
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100558 if (this->ofs != lastofs)
559 buggy = 1;
560 lastofs = this->ofs + this->size;
561 this = frag_next(this);
562 }
563
564 if (f->metadata)
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100565 printk(JFFS2_DBG "metadata at 0x%08x\n", ref_offset(f->metadata->raw));
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100566
567 if (buggy) {
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100568 JFFS2_ERROR("frag tree got a hole in it.\n");
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100569 BUG();
570 }
571}
572
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100573#define JFFS2_BUFDUMP_BYTES_PER_LINE 32
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100574void
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100575__jffs2_dbg_dump_buffer(unsigned char *buf, int len, uint32_t offs)
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100576{
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100577 int skip;
578 int i;
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000579
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100580 printk(JFFS2_DBG_MSG_PREFIX " dump from offset %#08x to offset %#08x (%x bytes).\n",
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100581 offs, offs + len, len);
582 i = skip = offs % JFFS2_BUFDUMP_BYTES_PER_LINE;
583 offs = offs & ~(JFFS2_BUFDUMP_BYTES_PER_LINE - 1);
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000584
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100585 if (skip != 0)
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100586 printk(JFFS2_DBG "%#08x: ", offs);
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000587
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100588 while (skip--)
589 printk(" ");
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100590
591 while (i < len) {
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100592 if ((i % JFFS2_BUFDUMP_BYTES_PER_LINE) == 0 && i != len -1) {
593 if (i != 0)
594 printk("\n");
595 offs += JFFS2_BUFDUMP_BYTES_PER_LINE;
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100596 printk(JFFS2_DBG "%0#8x: ", offs);
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100597 }
598
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100599 printk("%02x ", buf[i]);
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000600
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100601 i += 1;
602 }
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100603
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100604 printk("\n");
605}
606
607/*
608 * Dump a JFFS2 node.
609 */
610void
611__jffs2_dbg_dump_node(struct jffs2_sb_info *c, uint32_t ofs)
612{
613 union jffs2_node_union node;
614 int len = sizeof(union jffs2_node_union);
615 size_t retlen;
616 uint32_t crc;
617 int ret;
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000618
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100619 printk(JFFS2_DBG_MSG_PREFIX " dump node at offset %#08x.\n", ofs);
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100620
621 ret = jffs2_flash_read(c, ofs, len, &retlen, (unsigned char *)&node);
622 if (ret || (retlen != len)) {
623 JFFS2_ERROR("read %d bytes failed or short. ret %d, retlen %zd.\n",
624 len, ret, retlen);
625 return;
626 }
627
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100628 printk(JFFS2_DBG "magic:\t%#04x\n", je16_to_cpu(node.u.magic));
629 printk(JFFS2_DBG "nodetype:\t%#04x\n", je16_to_cpu(node.u.nodetype));
630 printk(JFFS2_DBG "totlen:\t%#08x\n", je32_to_cpu(node.u.totlen));
631 printk(JFFS2_DBG "hdr_crc:\t%#08x\n", je32_to_cpu(node.u.hdr_crc));
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000632
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100633 crc = crc32(0, &node.u, sizeof(node.u) - 4);
634 if (crc != je32_to_cpu(node.u.hdr_crc)) {
635 JFFS2_ERROR("wrong common header CRC.\n");
636 return;
637 }
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000638
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100639 if (je16_to_cpu(node.u.magic) != JFFS2_MAGIC_BITMASK &&
640 je16_to_cpu(node.u.magic) != JFFS2_OLD_MAGIC_BITMASK)
641 {
642 JFFS2_ERROR("wrong node magic: %#04x instead of %#04x.\n",
643 je16_to_cpu(node.u.magic), JFFS2_MAGIC_BITMASK);
644 return;
645 }
646
647 switch(je16_to_cpu(node.u.nodetype)) {
648
649 case JFFS2_NODETYPE_INODE:
650
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100651 printk(JFFS2_DBG "the node is inode node\n");
652 printk(JFFS2_DBG "ino:\t%#08x\n", je32_to_cpu(node.i.ino));
653 printk(JFFS2_DBG "version:\t%#08x\n", je32_to_cpu(node.i.version));
654 printk(JFFS2_DBG "mode:\t%#08x\n", node.i.mode.m);
655 printk(JFFS2_DBG "uid:\t%#04x\n", je16_to_cpu(node.i.uid));
656 printk(JFFS2_DBG "gid:\t%#04x\n", je16_to_cpu(node.i.gid));
657 printk(JFFS2_DBG "isize:\t%#08x\n", je32_to_cpu(node.i.isize));
658 printk(JFFS2_DBG "atime:\t%#08x\n", je32_to_cpu(node.i.atime));
659 printk(JFFS2_DBG "mtime:\t%#08x\n", je32_to_cpu(node.i.mtime));
660 printk(JFFS2_DBG "ctime:\t%#08x\n", je32_to_cpu(node.i.ctime));
661 printk(JFFS2_DBG "offset:\t%#08x\n", je32_to_cpu(node.i.offset));
662 printk(JFFS2_DBG "csize:\t%#08x\n", je32_to_cpu(node.i.csize));
663 printk(JFFS2_DBG "dsize:\t%#08x\n", je32_to_cpu(node.i.dsize));
664 printk(JFFS2_DBG "compr:\t%#02x\n", node.i.compr);
665 printk(JFFS2_DBG "usercompr:\t%#02x\n", node.i.usercompr);
666 printk(JFFS2_DBG "flags:\t%#04x\n", je16_to_cpu(node.i.flags));
667 printk(JFFS2_DBG "data_crc:\t%#08x\n", je32_to_cpu(node.i.data_crc));
668 printk(JFFS2_DBG "node_crc:\t%#08x\n", je32_to_cpu(node.i.node_crc));
669
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000670 crc = crc32(0, &node.i, sizeof(node.i) - 8);
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100671 if (crc != je32_to_cpu(node.i.node_crc)) {
672 JFFS2_ERROR("wrong node header CRC.\n");
673 return;
674 }
675 break;
676
677 case JFFS2_NODETYPE_DIRENT:
678
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100679 printk(JFFS2_DBG "the node is dirent node\n");
680 printk(JFFS2_DBG "pino:\t%#08x\n", je32_to_cpu(node.d.pino));
681 printk(JFFS2_DBG "version:\t%#08x\n", je32_to_cpu(node.d.version));
682 printk(JFFS2_DBG "ino:\t%#08x\n", je32_to_cpu(node.d.ino));
683 printk(JFFS2_DBG "mctime:\t%#08x\n", je32_to_cpu(node.d.mctime));
684 printk(JFFS2_DBG "nsize:\t%#02x\n", node.d.nsize);
685 printk(JFFS2_DBG "type:\t%#02x\n", node.d.type);
686 printk(JFFS2_DBG "node_crc:\t%#08x\n", je32_to_cpu(node.d.node_crc));
687 printk(JFFS2_DBG "name_crc:\t%#08x\n", je32_to_cpu(node.d.name_crc));
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000688
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100689 node.d.name[node.d.nsize] = '\0';
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100690 printk(JFFS2_DBG "name:\t\"%s\"\n", node.d.name);
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100691
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000692 crc = crc32(0, &node.d, sizeof(node.d) - 8);
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100693 if (crc != je32_to_cpu(node.d.node_crc)) {
694 JFFS2_ERROR("wrong node header CRC.\n");
695 return;
696 }
697 break;
698
699 default:
Artem B. Bityutskiy81e39cf2005-09-14 17:57:35 +0100700 printk(JFFS2_DBG "node type is unknown\n");
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100701 break;
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100702 }
703}
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100704#endif /* JFFS2_DBG_DUMPS || JFFS2_DBG_PARANOIA_CHECKS */