xref: /openbmc/linux/fs/jffs2/debug.c (revision 45ca1b50)
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.9 2005/08/05 10:42:24 dedekind Exp $
11  *
12  */
13 #include <linux/kernel.h>
14 #include <linux/types.h>
15 #include <linux/pagemap.h>
16 #include <linux/crc32.h>
17 #include <linux/jffs2.h>
18 #include "nodelist.h"
19 #include "debug.h"
20 
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 
59 #ifdef JFFS2_DBG_PARANOIA_CHECKS
60 /*
61  * Check the fragtree.
62  */
63 void
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)
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) {
85 				JFFS2_ERROR("REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2.\n",
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) {
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));
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) {
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",
106 					       ref_offset(fn->raw), frag->ofs, frag->ofs+frag->size);
107 				bitched = 1;
108 			}
109 		}
110 	}
111 
112 	if (bitched) {
113 		JFFS2_ERROR("fragtree is corrupted.\n");
114 		__jffs2_dbg_dump_fragtree_nolock(f);
115 		BUG();
116 	}
117 }
118 
119 /*
120  * Check if the flash contains all 0xFF before we start writing.
121  */
122 void
123 __jffs2_dbg_prewrite_paranoia_check(struct jffs2_sb_info *c,
124 				    uint32_t ofs, int len)
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)) {
136 		JFFS2_WARNING("read %d bytes failed or short. ret %d, retlen %zd.\n",
137 				len, ret, retlen);
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) {
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);
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
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)
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) {
184 			JFFS2_ERROR("node_ref %#08x shouldn't be in block at %#08x.\n",
185 				ref_offset(ref2), jeb->offset);
186 			goto error;
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)) {
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;
202 		}
203 		ref2 = ref2->next_phys;
204 	}
205 
206 	if (my_used_size != jeb->used_size) {
207 		JFFS2_ERROR("Calculated used size %#08x != stored used size %#08x.\n",
208 			my_used_size, jeb->used_size);
209 		goto error;
210 	}
211 
212 	if (my_unchecked_size != jeb->unchecked_size) {
213 		JFFS2_ERROR("Calculated unchecked size %#08x != stored unchecked size %#08x.\n",
214 			my_unchecked_size, jeb->unchecked_size);
215 		goto error;
216 	}
217 
218 #if 0
219 	/* This should work when we implement ref->__totlen elemination */
220 	if (my_dirty_size != jeb->dirty_size + jeb->wasted_size) {
221 		JFFS2_ERROR("Calculated dirty+wasted size %#08x != stored dirty + wasted size %#08x\n",
222 			my_dirty_size, jeb->dirty_size + jeb->wasted_size);
223 		goto error;
224 	}
225 
226 	if (jeb->free_size == 0
227 		&& my_used_size + my_unchecked_size + my_dirty_size != c->sector_size) {
228 		JFFS2_ERROR("The sum of all nodes in block (%#x) != size of block (%#x)\n",
229 			my_used_size + my_unchecked_size + my_dirty_size,
230 			c->sector_size);
231 		goto error;
232 	}
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 
243 }
244 #endif /* JFFS2_DBG_PARANOIA_CHECKS */
245 
246 #if defined(JFFS2_DBG_DUMPS) || defined(JFFS2_DBG_PARANOIA_CHECKS)
247 /*
248  * Dump the node_refs of the 'jeb' JFFS2 eraseblock.
249  */
250 void
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)
262 {
263 	struct jffs2_raw_node_ref *ref;
264 	int i = 0;
265 
266 	JFFS2_DEBUG("Dump node_refs of the eraseblock %#08x\n", jeb->offset);
267 	if (!jeb->first_node) {
268 		JFFS2_DEBUG("no nodes in the eraseblock %#08x\n", jeb->offset);
269 		return;
270 	}
271 
272 	printk(JFFS2_DBG_LVL);
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;
281 			printk("\n" JFFS2_DBG_LVL);
282 		}
283 	}
284 	printk("\n");
285 }
286 
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 
298 void
299 __jffs2_dbg_dump_jeb_nolock(struct jffs2_eraseblock *jeb)
300 {
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",
337 				c->sector_size * c->resv_blocks_write);
338 
339 	if (c->nextblock)
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);
345 	else
346 		printk(JFFS2_DBG_LVL "nextblock: NULL\n");
347 
348 	if (c->gcblock)
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);
353 	else
354 		printk(JFFS2_DBG_LVL "gcblock: NULL\n");
355 
356 	if (list_empty(&c->clean_list)) {
357 		printk(JFFS2_DBG_LVL "clean_list: empty\n");
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)) {
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);
372 			}
373 		}
374 
375 		printk (JFFS2_DBG_LVL "Contains %d blocks with total wasted size %u, average wasted size: %u\n",
376 			numblocks, dirty, dirty / numblocks);
377 	}
378 
379 	if (list_empty(&c->very_dirty_list)) {
380 		printk(JFFS2_DBG_LVL "very_dirty_list: empty\n");
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)) {
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);
396 			}
397 		}
398 
399 		printk (JFFS2_DBG_LVL "Contains %d blocks with total dirty size %u, average dirty size: %u\n",
400 			numblocks, dirty, dirty / numblocks);
401 	}
402 
403 	if (list_empty(&c->dirty_list)) {
404 		printk(JFFS2_DBG_LVL "dirty_list: empty\n");
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)) {
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);
420 			}
421 		}
422 
423 		printk (JFFS2_DBG_LVL "contains %d blocks with total dirty size %u, average dirty size: %u\n",
424 			numblocks, dirty, dirty / numblocks);
425 	}
426 
427 	if (list_empty(&c->erasable_list)) {
428 		printk(JFFS2_DBG_LVL "erasable_list: empty\n");
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)) {
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);
440 			}
441 		}
442 	}
443 
444 	if (list_empty(&c->erasing_list)) {
445 		printk(JFFS2_DBG_LVL "erasing_list: empty\n");
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)) {
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);
457 			}
458 		}
459 	}
460 
461 	if (list_empty(&c->erase_pending_list)) {
462 		printk(JFFS2_DBG_LVL "erase_pending_list: empty\n");
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)) {
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);
474 			}
475 		}
476 	}
477 
478 	if (list_empty(&c->erasable_pending_wbuf_list)) {
479 		printk(JFFS2_DBG_LVL "erasable_pending_wbuf_list: empty\n");
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)) {
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);
491 			}
492 		}
493 	}
494 
495 	if (list_empty(&c->free_list)) {
496 		printk(JFFS2_DBG_LVL "free_list: empty\n");
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)) {
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);
508 			}
509 		}
510 	}
511 
512 	if (list_empty(&c->bad_list)) {
513 		printk(JFFS2_DBG_LVL "bad_list: empty\n");
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)) {
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);
525 			}
526 		}
527 	}
528 
529 	if (list_empty(&c->bad_used_list)) {
530 		printk(JFFS2_DBG_LVL "bad_used_list: empty\n");
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)) {
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);
542 			}
543 		}
544 	}
545 }
546 
547 void
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)
557 {
558 	struct jffs2_node_frag *this = frag_first(&f->fragtree);
559 	uint32_t lastofs = 0;
560 	int buggy = 0;
561 
562 	JFFS2_DEBUG("dump fragtree of ino #%u\n", f->inocache->ino);
563 	while(this) {
564 		if (this->node)
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));
570 		else
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));
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)
581 		printk(JFFS2_DBG_LVL "metadata at 0x%08x\n", ref_offset(f->metadata->raw));
582 
583 	if (buggy) {
584 		JFFS2_ERROR("frag tree got a hole in it.\n");
585 		BUG();
586 	}
587 }
588 
589 #define JFFS2_BUFDUMP_BYTES_PER_LINE	32
590 void
591 __jffs2_dbg_dump_buffer(unsigned char *buf, int len, uint32_t offs)
592 {
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("   ");
606 
607 	while (i < len) {
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);
613 		}
614 
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;
740 		}
741 		break;
742 
743 	default:
744 		printk(JFFS2_DBG_LVL "node type is unknown\n");
745 		break;
746 	}
747 }
748 #endif /* JFFS2_DBG_DUMPS || JFFS2_DBG_PARANOIA_CHECKS */
749