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