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