xref: /openbmc/linux/fs/jffs2/debug.c (revision 730554d9)
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  *
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 
20 void
21 jffs2_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  */
71 void
72 jffs2_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  */
109 void
110 jffs2_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  */
188 void
189 jffs2_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 
214 void
215 jffs2_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 
437 void
438 jffs2_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
472 void
473 jffs2_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 */
496