blob: 9da524ca4e66ea813503961b2b0da80bd00dede5 [file] [log] [blame]
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +01001/*
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 *
10 * $Id: debug.c,v 1.1 2005/07/17 06:56:20 dedekind Exp $
11 *
12 */
13#include <linux/kernel.h>
14#include <linux/pagemap.h>
15#include "nodelist.h"
16#include "debug.h"
17
18#ifdef JFFS2_DBG_PARANOIA_CHECKS
19
20void
21jffs2_dbg_fragtree_paranoia_check(struct jffs2_inode_info *f)
22{
23 struct jffs2_node_frag *frag;
24 int bitched = 0;
25
26 for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) {
27 struct jffs2_full_dnode *fn = frag->node;
28
29 if (!fn || !fn->raw)
30 continue;
31
32 if (ref_flags(fn->raw) == REF_PRISTINE) {
33 if (fn->frags > 1) {
34 printk(KERN_ERR "REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2\n",
35 ref_offset(fn->raw), fn->frags);
36 bitched = 1;
37 }
38
39 /* A hole node which isn't multi-page should be garbage-collected
40 and merged anyway, so we just check for the frag size here,
41 rather than mucking around with actually reading the node
42 and checking the compression type, which is the real way
43 to tell a hole node. */
44 if (frag->ofs & (PAGE_CACHE_SIZE-1) && frag_prev(frag)
45 && frag_prev(frag)->size < PAGE_CACHE_SIZE && frag_prev(frag)->node) {
46 printk(KERN_ERR "REF_PRISTINE node at 0x%08x had a previous non-hole frag "
47 "in the same page. Tell dwmw2\n", ref_offset(fn->raw));
48 bitched = 1;
49 }
50
51 if ((frag->ofs+frag->size) & (PAGE_CACHE_SIZE-1) && frag_next(frag)
52 && frag_next(frag)->size < PAGE_CACHE_SIZE && frag_next(frag)->node) {
53 printk(KERN_ERR "REF_PRISTINE node at 0x%08x (%08x-%08x) had a following "
54 "non-hole frag in the same page. Tell dwmw2\n",
55 ref_offset(fn->raw), frag->ofs, frag->ofs+frag->size);
56 bitched = 1;
57 }
58 }
59 }
60
61 if (bitched) {
62 printk(KERN_ERR "Fragtree is corrupted. Fragtree dump:\n");
63 jffs2_dbg_dump_fragtree(f);
64 BUG();
65 }
66}
67
68/*
69 * Check if the flash contains all 0xFF before we start writing.
70 */
71void
72jffs2_dbg_prewrite_paranoia_check(struct jffs2_sb_info *c, uint32_t ofs, int len)
73{
74 size_t retlen;
75 int ret, i;
76 unsigned char *buf;
77
78 buf = kmalloc(len, GFP_KERNEL);
79 if (!buf)
80 return;
81
82 ret = jffs2_flash_read(c, ofs, len, &retlen, buf);
83 if (ret || (retlen != len)) {
84 printk(KERN_WARNING "read %d bytes failed or short in %s(). ret %d, retlen %zd\n",
85 len, __FUNCTION__, ret, retlen);
86 kfree(buf);
87 return;
88 }
89
90 ret = 0;
91 for (i = 0; i < len; i++)
92 if (buf[i] != 0xff)
93 ret = 1;
94
95 if (ret) {
96 printk(KERN_ERR "ARGH. About to write node to %#08x on flash, but there are data "
97 "already there. The first corrupted byte is at %#08x.\n", ofs, ofs + i);
98 jffs2_dbg_dump_buffer(buf, len, ofs);
99 kfree(buf);
100 BUG();
101 }
102
103 kfree(buf);
104}
105
106/*
107 * Check the space accounting and node_ref list correctness for the JFFS2 erasable block 'jeb'.
108 */
109void
110jffs2_dbg_acct_paranoia_check(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
111{
112 uint32_t my_used_size = 0;
113 uint32_t my_unchecked_size = 0;
114 uint32_t my_dirty_size = 0;
115 struct jffs2_raw_node_ref *ref2 = jeb->first_node;
116
117 while (ref2) {
118 uint32_t totlen = ref_totlen(c, jeb, ref2);
119
120 if (ref2->flash_offset < jeb->offset ||
121 ref2->flash_offset > jeb->offset + c->sector_size) {
122 printk(KERN_ERR "node_ref %#08x shouldn't be in block at %#08x!\n",
123 ref_offset(ref2), jeb->offset);
124 jffs2_dbg_dump_node_refs(c, jeb);
125 jffs2_dbg_dump_block_lists(c);
126 BUG();
127
128 }
129 if (ref_flags(ref2) == REF_UNCHECKED)
130 my_unchecked_size += totlen;
131 else if (!ref_obsolete(ref2))
132 my_used_size += totlen;
133 else
134 my_dirty_size += totlen;
135
136 if ((!ref2->next_phys) != (ref2 == jeb->last_node)) {
137 printk(KERN_ERR "node_ref for node at %#08x (mem %p) has next_phys at %#08x (mem %p), "
138 "last_node is at %#08x (mem %p)\n",
139 ref_offset(ref2), ref2, ref_offset(ref2->next_phys), ref2->next_phys,
140 ref_offset(jeb->last_node), jeb->last_node);
141 jffs2_dbg_dump_node_refs(c, jeb);
142 jffs2_dbg_dump_block_lists(c);
143 BUG();
144 }
145 ref2 = ref2->next_phys;
146 }
147
148 if (my_used_size != jeb->used_size) {
149 printk(KERN_ERR "Calculated used size %#08x != stored used size %#08x\n",
150 my_used_size, jeb->used_size);
151 jffs2_dbg_dump_node_refs(c, jeb);
152 jffs2_dbg_dump_block_lists(c);
153 BUG();
154 }
155
156 if (my_unchecked_size != jeb->unchecked_size) {
157 printk(KERN_ERR "Calculated unchecked size %#08x != stored unchecked size %#08x\n",
158 my_unchecked_size, jeb->unchecked_size);
159 jffs2_dbg_dump_node_refs(c, jeb);
160 jffs2_dbg_dump_block_lists(c);
161 BUG();
162 }
163
164 if (my_dirty_size != jeb->dirty_size + jeb->wasted_size) {
165 printk(KERN_ERR "Calculated dirty+wasted size %#08x != stored dirty + wasted size %#08x\n",
166 my_dirty_size, jeb->dirty_size + jeb->wasted_size);
167 jffs2_dbg_dump_node_refs(c, jeb);
168 jffs2_dbg_dump_block_lists(c);
169 BUG();
170 }
171
172 if (jeb->free_size == 0
173 && my_used_size + my_unchecked_size + my_dirty_size != c->sector_size) {
174 printk(KERN_ERR "The sum of all nodes in block (%#x) != size of block (%#x)\n",
175 my_used_size + my_unchecked_size + my_dirty_size,
176 c->sector_size);
177 jffs2_dbg_dump_node_refs(c, jeb);
178 jffs2_dbg_dump_block_lists(c);
179 BUG();
180 }
181}
182#endif /* JFFS2_PARANOIA_CHECKS */
183
184#if defined(JFFS2_PARANOIA_CHECKS) || (CONFIG_JFFS2_FS_DEBUG > 0)
185/*
186 * Dump the node_refs of the 'jeb' JFFS2 eraseblock.
187 */
188void
189jffs2_dbg_dump_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
190{
191 struct jffs2_raw_node_ref *ref;
192 int i = 0;
193
194 if (!jeb->first_node) {
195 printk(KERN_DEBUG "no nodes in block %#08x\n", jeb->offset);
196 return;
197 }
198
199 printk(KERN_DEBUG);
200 for (ref = jeb->first_node; ; ref = ref->next_phys) {
201 printk("%#08x(%#x)", ref_offset(ref), ref->__totlen);
202 if (ref->next_phys)
203 printk("->");
204 else
205 break;
206 if (++i == 4) {
207 i = 0;
208 printk("\n" KERN_DEBUG);
209 }
210 }
211 printk("\n");
212}
213
214void
215jffs2_dbg_dump_block_lists(struct jffs2_sb_info *c)
216{
217 printk(KERN_DEBUG "flash_size: %#08x\n", c->flash_size);
218 printk(KERN_DEBUG "used_size: %#08x\n", c->used_size);
219 printk(KERN_DEBUG "dirty_size: %#08x\n", c->dirty_size);
220 printk(KERN_DEBUG "wasted_size: %#08x\n", c->wasted_size);
221 printk(KERN_DEBUG "unchecked_size: %#08x\n", c->unchecked_size);
222 printk(KERN_DEBUG "free_size: %#08x\n", c->free_size);
223 printk(KERN_DEBUG "erasing_size: %#08x\n", c->erasing_size);
224 printk(KERN_DEBUG "bad_size: %#08x\n", c->bad_size);
225 printk(KERN_DEBUG "sector_size: %#08x\n", c->sector_size);
226 printk(KERN_DEBUG "jffs2_reserved_blocks size: %#08x\n",
227 c->sector_size * c->resv_blocks_write);
228
229 if (c->nextblock)
230 printk(KERN_DEBUG "nextblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, "
231 "unchecked %#08x, free %#08x)\n",
232 c->nextblock->offset, c->nextblock->used_size,
233 c->nextblock->dirty_size, c->nextblock->wasted_size,
234 c->nextblock->unchecked_size, c->nextblock->free_size);
235 else
236 printk(KERN_DEBUG "nextblock: NULL\n");
237
238 if (c->gcblock)
239 printk(KERN_DEBUG "gcblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, "
240 "unchecked %#08x, free %#08x)\n",
241 c->gcblock->offset, c->gcblock->used_size, c->gcblock->dirty_size,
242 c->gcblock->wasted_size, c->gcblock->unchecked_size, c->gcblock->free_size);
243 else
244 printk(KERN_DEBUG "gcblock: NULL\n");
245
246 if (list_empty(&c->clean_list)) {
247 printk(KERN_DEBUG "clean_list: empty\n");
248 } else {
249 struct list_head *this;
250 int numblocks = 0;
251 uint32_t dirty = 0;
252
253 list_for_each(this, &c->clean_list) {
254 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
255 numblocks ++;
256 dirty += jeb->wasted_size;
257 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
258 printk(KERN_DEBUG "clean_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, "
259 "unchecked %#08x, free %#08x)\n",
260 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
261 jeb->unchecked_size, jeb->free_size);
262 }
263 }
264
265 printk (KERN_DEBUG "Contains %d blocks with total wasted size %u, average wasted size: %u\n",
266 numblocks, dirty, dirty / numblocks);
267 }
268
269 if (list_empty(&c->very_dirty_list)) {
270 printk(KERN_DEBUG "very_dirty_list: empty\n");
271 } else {
272 struct list_head *this;
273 int numblocks = 0;
274 uint32_t dirty = 0;
275
276 list_for_each(this, &c->very_dirty_list) {
277 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
278
279 numblocks ++;
280 dirty += jeb->dirty_size;
281 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
282 printk(KERN_DEBUG "very_dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, "
283 "unchecked %#08x, free %#08x)\n",
284 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
285 jeb->unchecked_size, jeb->free_size);
286 }
287 }
288
289 printk (KERN_DEBUG "Contains %d blocks with total dirty size %u, average dirty size: %u\n",
290 numblocks, dirty, dirty / numblocks);
291 }
292
293 if (list_empty(&c->dirty_list)) {
294 printk(KERN_DEBUG "dirty_list: empty\n");
295 } else {
296 struct list_head *this;
297 int numblocks = 0;
298 uint32_t dirty = 0;
299
300 list_for_each(this, &c->dirty_list) {
301 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
302
303 numblocks ++;
304 dirty += jeb->dirty_size;
305 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
306 printk(KERN_DEBUG "dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, "
307 "unchecked %#08x, free %#08x)\n",
308 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
309 jeb->unchecked_size, jeb->free_size);
310 }
311 }
312
313 printk (KERN_DEBUG "Contains %d blocks with total dirty size %u, average dirty size: %u\n",
314 numblocks, dirty, dirty / numblocks);
315 }
316
317 if (list_empty(&c->erasable_list)) {
318 printk(KERN_DEBUG "erasable_list: empty\n");
319 } else {
320 struct list_head *this;
321
322 list_for_each(this, &c->erasable_list) {
323 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
324
325 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
326 printk(KERN_DEBUG "erasable_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, "
327 "unchecked %#08x, free %#08x)\n",
328 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
329 jeb->unchecked_size, jeb->free_size);
330 }
331 }
332 }
333
334 if (list_empty(&c->erasing_list)) {
335 printk(KERN_DEBUG "erasing_list: empty\n");
336 } else {
337 struct list_head *this;
338
339 list_for_each(this, &c->erasing_list) {
340 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
341
342 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
343 printk(KERN_DEBUG "erasing_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, "
344 "unchecked %#08x, free %#08x)\n",
345 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
346 jeb->unchecked_size, jeb->free_size);
347 }
348 }
349 }
350
351 if (list_empty(&c->erase_pending_list)) {
352 printk(KERN_DEBUG "erase_pending_list: empty\n");
353 } else {
354 struct list_head *this;
355
356 list_for_each(this, &c->erase_pending_list) {
357 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
358
359 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
360 printk(KERN_DEBUG "erase_pending_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, "
361 "unchecked %#08x, free %#08x)\n",
362 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
363 jeb->unchecked_size, jeb->free_size);
364 }
365 }
366 }
367
368 if (list_empty(&c->erasable_pending_wbuf_list)) {
369 printk(KERN_DEBUG "erasable_pending_wbuf_list: empty\n");
370 } else {
371 struct list_head *this;
372
373 list_for_each(this, &c->erasable_pending_wbuf_list) {
374 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
375
376 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
377 printk(KERN_DEBUG "erasable_pending_wbuf_list: %#08x (used %#08x, dirty %#08x, "
378 "wasted %#08x, unchecked %#08x, free %#08x)\n",
379 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
380 jeb->unchecked_size, jeb->free_size);
381 }
382 }
383 }
384
385 if (list_empty(&c->free_list)) {
386 printk(KERN_DEBUG "free_list: empty\n");
387 } else {
388 struct list_head *this;
389
390 list_for_each(this, &c->free_list) {
391 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
392
393 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
394 printk(KERN_DEBUG "free_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, "
395 "unchecked %#08x, free %#08x)\n",
396 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
397 jeb->unchecked_size, jeb->free_size);
398 }
399 }
400 }
401
402 if (list_empty(&c->bad_list)) {
403 printk(KERN_DEBUG "bad_list: empty\n");
404 } else {
405 struct list_head *this;
406
407 list_for_each(this, &c->bad_list) {
408 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
409
410 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
411 printk(KERN_DEBUG "bad_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, "
412 "unchecked %#08x, free %#08x)\n",
413 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
414 jeb->unchecked_size, jeb->free_size);
415 }
416 }
417 }
418
419 if (list_empty(&c->bad_used_list)) {
420 printk(KERN_DEBUG "bad_used_list: empty\n");
421 } else {
422 struct list_head *this;
423
424 list_for_each(this, &c->bad_used_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)) {
428 printk(KERN_DEBUG "bad_used_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, "
429 "unchecked %#08x, free %#08x)\n",
430 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
431 jeb->unchecked_size, jeb->free_size);
432 }
433 }
434 }
435}
436
437void
438jffs2_dbg_dump_fragtree(struct jffs2_inode_info *f)
439{
440 struct jffs2_node_frag *this = frag_first(&f->fragtree);
441 uint32_t lastofs = 0;
442 int buggy = 0;
443
444 printk(KERN_DEBUG "inode is ino #%u\n", f->inocache->ino);
445 while(this) {
446 if (this->node)
447 printk(KERN_DEBUG "frag %#04x-%#04x: %#08x(%d) on flash (*%p), left (%p), "
448 "right (%p), parent (%p)\n",
449 this->ofs, this->ofs+this->size, ref_offset(this->node->raw),
450 ref_flags(this->node->raw), this, frag_left(this), frag_right(this),
451 frag_parent(this));
452 else
453 printk(KERN_DEBUG "frag %#04x-%#04x: hole (*%p). left (%p), right (%p), parent (%p)\n",
454 this->ofs, this->ofs+this->size, this, frag_left(this),
455 frag_right(this), frag_parent(this));
456 if (this->ofs != lastofs)
457 buggy = 1;
458 lastofs = this->ofs + this->size;
459 this = frag_next(this);
460 }
461
462 if (f->metadata)
463 printk(KERN_DEBUG "metadata at 0x%08x\n", ref_offset(f->metadata->raw));
464
465 if (buggy) {
466 printk(KERN_ERR "Error! %s(): Frag tree got a hole in it\n", __FUNCTION__);
467 BUG();
468 }
469}
470
471#define JFFS3_BUFDUMP_BYTES_PER_LINE 8
472void
473jffs2_dbg_dump_buffer(char *buf, int len, uint32_t offs)
474{
475 int i = 0;
476 int skip = offs & ~(JFFS3_BUFDUMP_BYTES_PER_LINE - 1);
477
478 while (i < len) {
479 int j = 0;
480
481 printk(KERN_DEBUG "0x#x: \n");
482 while (skip) {
483 printk(" ");
484 skip -= 1;
485 }
486
487 while (j < JFFS3_BUFDUMP_BYTES_PER_LINE) {
488 if (i + j < len)
489 printk(" %#02x", buf[i + j++]);
490 }
491
492 i += JFFS3_BUFDUMP_BYTES_PER_LINE;
493 }
494}
495#endif /* JFFS2_PARANOIA_CHECKS || CONFIG_JFFS2_FS_DEBUG > 0 */