xref: /linux/fs/jffs2/debug.c (revision abb536e7)
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.12 2005/11/07 11:14:39 gleixner 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 <linux/mtd/mtd.h>
19 #include "nodelist.h"
20 #include "debug.h"
21 
22 #ifdef JFFS2_DBG_SANITY_CHECKS
23 
24 void
25 __jffs2_dbg_acct_sanity_check_nolock(struct jffs2_sb_info *c,
26 				     struct jffs2_eraseblock *jeb)
27 {
28 	if (unlikely(jeb && jeb->used_size + jeb->dirty_size +
29 			jeb->free_size + jeb->wasted_size +
30 			jeb->unchecked_size != c->sector_size)) {
31 		JFFS2_ERROR("eeep, space accounting for block at 0x%08x is screwed.\n", jeb->offset);
32 		JFFS2_ERROR("free %#08x + dirty %#08x + used %#08x + wasted %#08x + unchecked %#08x != total %#08x.\n",
33 			jeb->free_size, jeb->dirty_size, jeb->used_size,
34 			jeb->wasted_size, jeb->unchecked_size, c->sector_size);
35 		BUG();
36 	}
37 
38 	if (unlikely(c->used_size + c->dirty_size + c->free_size + c->erasing_size + c->bad_size
39 				+ c->wasted_size + c->unchecked_size != c->flash_size)) {
40 		JFFS2_ERROR("eeep, space accounting superblock info is screwed.\n");
41 		JFFS2_ERROR("free %#08x + dirty %#08x + used %#08x + erasing %#08x + bad %#08x + 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 in the same page. Tell dwmw2.\n",
98 					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 non-hole frag in the same page. Tell dwmw2.\n",
105 				       ref_offset(fn->raw), frag->ofs, frag->ofs+frag->size);
106 				bitched = 1;
107 			}
108 		}
109 	}
110 
111 	if (bitched) {
112 		JFFS2_ERROR("fragtree is corrupted.\n");
113 		__jffs2_dbg_dump_fragtree_nolock(f);
114 		BUG();
115 	}
116 }
117 
118 /*
119  * Check if the flash contains all 0xFF before we start writing.
120  */
121 void
122 __jffs2_dbg_prewrite_paranoia_check(struct jffs2_sb_info *c,
123 				    uint32_t ofs, int len)
124 {
125 	size_t retlen;
126 	int ret, i;
127 	unsigned char *buf;
128 
129 	buf = kmalloc(len, GFP_KERNEL);
130 	if (!buf)
131 		return;
132 
133 	ret = jffs2_flash_read(c, ofs, len, &retlen, buf);
134 	if (ret || (retlen != len)) {
135 		JFFS2_WARNING("read %d bytes failed or short. ret %d, retlen %zd.\n",
136 				len, ret, retlen);
137 		kfree(buf);
138 		return;
139 	}
140 
141 	ret = 0;
142 	for (i = 0; i < len; i++)
143 		if (buf[i] != 0xff)
144 			ret = 1;
145 
146 	if (ret) {
147 		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",
148 			ofs, ofs + i);
149 		__jffs2_dbg_dump_buffer(buf, len, ofs);
150 		kfree(buf);
151 		BUG();
152 	}
153 
154 	kfree(buf);
155 }
156 
157 /*
158  * Check the space accounting and node_ref list correctness for the JFFS2 erasable block 'jeb'.
159  */
160 void
161 __jffs2_dbg_acct_paranoia_check(struct jffs2_sb_info *c,
162 				struct jffs2_eraseblock *jeb)
163 {
164 	spin_lock(&c->erase_completion_lock);
165 	__jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
166 	spin_unlock(&c->erase_completion_lock);
167 }
168 
169 void
170 __jffs2_dbg_acct_paranoia_check_nolock(struct jffs2_sb_info *c,
171 				       struct jffs2_eraseblock *jeb)
172 {
173 	uint32_t my_used_size = 0;
174 	uint32_t my_unchecked_size = 0;
175 	uint32_t my_dirty_size = 0;
176 	struct jffs2_raw_node_ref *ref2 = jeb->first_node;
177 
178 	while (ref2) {
179 		uint32_t totlen = ref_totlen(c, jeb, ref2);
180 
181 		if (ref_offset(ref2) < jeb->offset ||
182 				ref_offset(ref2) > jeb->offset + c->sector_size) {
183 			JFFS2_ERROR("node_ref %#08x shouldn't be in block at %#08x.\n",
184 				ref_offset(ref2), jeb->offset);
185 			goto error;
186 
187 		}
188 		if (ref_flags(ref2) == REF_UNCHECKED)
189 			my_unchecked_size += totlen;
190 		else if (!ref_obsolete(ref2))
191 			my_used_size += totlen;
192 		else
193 			my_dirty_size += totlen;
194 
195 		if ((!ref_next(ref2)) != (ref2 == jeb->last_node)) {
196 			JFFS2_ERROR("node_ref for node at %#08x (mem %p) has next at %#08x (mem %p), last_node is at %#08x (mem %p).\n",
197 				    ref_offset(ref2), ref2, ref_offset(ref_next(ref2)), ref_next(ref2),
198 				    ref_offset(jeb->last_node), jeb->last_node);
199 			goto error;
200 		}
201 		ref2 = ref_next(ref2);
202 	}
203 
204 	if (my_used_size != jeb->used_size) {
205 		JFFS2_ERROR("Calculated used size %#08x != stored used size %#08x.\n",
206 			my_used_size, jeb->used_size);
207 		goto error;
208 	}
209 
210 	if (my_unchecked_size != jeb->unchecked_size) {
211 		JFFS2_ERROR("Calculated unchecked size %#08x != stored unchecked size %#08x.\n",
212 			my_unchecked_size, jeb->unchecked_size);
213 		goto error;
214 	}
215 
216 #if 0
217 	/* This should work when we implement ref->__totlen elemination */
218 	if (my_dirty_size != jeb->dirty_size + jeb->wasted_size) {
219 		JFFS2_ERROR("Calculated dirty+wasted size %#08x != stored dirty + wasted size %#08x\n",
220 			my_dirty_size, jeb->dirty_size + jeb->wasted_size);
221 		goto error;
222 	}
223 
224 	if (jeb->free_size == 0
225 		&& my_used_size + my_unchecked_size + my_dirty_size != c->sector_size) {
226 		JFFS2_ERROR("The sum of all nodes in block (%#x) != size of block (%#x)\n",
227 			my_used_size + my_unchecked_size + my_dirty_size,
228 			c->sector_size);
229 		goto error;
230 	}
231 #endif
232 
233 	return;
234 
235 error:
236 	__jffs2_dbg_dump_node_refs_nolock(c, jeb);
237 	__jffs2_dbg_dump_jeb_nolock(jeb);
238 	__jffs2_dbg_dump_block_lists_nolock(c);
239 	BUG();
240 
241 }
242 #endif /* JFFS2_DBG_PARANOIA_CHECKS */
243 
244 #if defined(JFFS2_DBG_DUMPS) || defined(JFFS2_DBG_PARANOIA_CHECKS)
245 /*
246  * Dump the node_refs of the 'jeb' JFFS2 eraseblock.
247  */
248 void
249 __jffs2_dbg_dump_node_refs(struct jffs2_sb_info *c,
250 			   struct jffs2_eraseblock *jeb)
251 {
252 	spin_lock(&c->erase_completion_lock);
253 	__jffs2_dbg_dump_node_refs_nolock(c, jeb);
254 	spin_unlock(&c->erase_completion_lock);
255 }
256 
257 void
258 __jffs2_dbg_dump_node_refs_nolock(struct jffs2_sb_info *c,
259 				  struct jffs2_eraseblock *jeb)
260 {
261 	struct jffs2_raw_node_ref *ref;
262 	int i = 0;
263 
264 	printk(JFFS2_DBG_MSG_PREFIX " Dump node_refs of the eraseblock %#08x\n", jeb->offset);
265 	if (!jeb->first_node) {
266 		printk(JFFS2_DBG_MSG_PREFIX " no nodes in the eraseblock %#08x\n", jeb->offset);
267 		return;
268 	}
269 
270 	printk(JFFS2_DBG);
271 	for (ref = jeb->first_node; ; ref = ref_next(ref)) {
272 		printk("%#08x(%#x)", ref_offset(ref), ref->__totlen);
273 		if (ref_next(ref))
274 			printk("->");
275 		else
276 			break;
277 		if (++i == 4) {
278 			i = 0;
279 			printk("\n" JFFS2_DBG);
280 		}
281 	}
282 	printk("\n");
283 }
284 
285 /*
286  * Dump an eraseblock's space accounting.
287  */
288 void
289 __jffs2_dbg_dump_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
290 {
291 	spin_lock(&c->erase_completion_lock);
292 	__jffs2_dbg_dump_jeb_nolock(jeb);
293 	spin_unlock(&c->erase_completion_lock);
294 }
295 
296 void
297 __jffs2_dbg_dump_jeb_nolock(struct jffs2_eraseblock *jeb)
298 {
299 	if (!jeb)
300 		return;
301 
302 	printk(JFFS2_DBG_MSG_PREFIX " dump space accounting for the eraseblock at %#08x:\n",
303 			jeb->offset);
304 
305 	printk(JFFS2_DBG "used_size: %#08x\n",		jeb->used_size);
306 	printk(JFFS2_DBG "dirty_size: %#08x\n",		jeb->dirty_size);
307 	printk(JFFS2_DBG "wasted_size: %#08x\n",	jeb->wasted_size);
308 	printk(JFFS2_DBG "unchecked_size: %#08x\n",	jeb->unchecked_size);
309 	printk(JFFS2_DBG "free_size: %#08x\n",		jeb->free_size);
310 }
311 
312 void
313 __jffs2_dbg_dump_block_lists(struct jffs2_sb_info *c)
314 {
315 	spin_lock(&c->erase_completion_lock);
316 	__jffs2_dbg_dump_block_lists_nolock(c);
317 	spin_unlock(&c->erase_completion_lock);
318 }
319 
320 void
321 __jffs2_dbg_dump_block_lists_nolock(struct jffs2_sb_info *c)
322 {
323 	printk(JFFS2_DBG_MSG_PREFIX " dump JFFS2 blocks lists:\n");
324 
325 	printk(JFFS2_DBG "flash_size: %#08x\n",		c->flash_size);
326 	printk(JFFS2_DBG "used_size: %#08x\n",		c->used_size);
327 	printk(JFFS2_DBG "dirty_size: %#08x\n",		c->dirty_size);
328 	printk(JFFS2_DBG "wasted_size: %#08x\n",	c->wasted_size);
329 	printk(JFFS2_DBG "unchecked_size: %#08x\n",	c->unchecked_size);
330 	printk(JFFS2_DBG "free_size: %#08x\n",		c->free_size);
331 	printk(JFFS2_DBG "erasing_size: %#08x\n",	c->erasing_size);
332 	printk(JFFS2_DBG "bad_size: %#08x\n",		c->bad_size);
333 	printk(JFFS2_DBG "sector_size: %#08x\n",	c->sector_size);
334 	printk(JFFS2_DBG "jffs2_reserved_blocks size: %#08x\n",
335 				c->sector_size * c->resv_blocks_write);
336 
337 	if (c->nextblock)
338 		printk(JFFS2_DBG "nextblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
339 			c->nextblock->offset, c->nextblock->used_size,
340 			c->nextblock->dirty_size, c->nextblock->wasted_size,
341 			c->nextblock->unchecked_size, c->nextblock->free_size);
342 	else
343 		printk(JFFS2_DBG "nextblock: NULL\n");
344 
345 	if (c->gcblock)
346 		printk(JFFS2_DBG "gcblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
347 			c->gcblock->offset, c->gcblock->used_size, c->gcblock->dirty_size,
348 			c->gcblock->wasted_size, c->gcblock->unchecked_size, c->gcblock->free_size);
349 	else
350 		printk(JFFS2_DBG "gcblock: NULL\n");
351 
352 	if (list_empty(&c->clean_list)) {
353 		printk(JFFS2_DBG "clean_list: empty\n");
354 	} else {
355 		struct list_head *this;
356 		int numblocks = 0;
357 		uint32_t dirty = 0;
358 
359 		list_for_each(this, &c->clean_list) {
360 			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
361 			numblocks ++;
362 			dirty += jeb->wasted_size;
363 			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
364 				printk(JFFS2_DBG "clean_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
365 					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
366 					jeb->unchecked_size, jeb->free_size);
367 			}
368 		}
369 
370 		printk (JFFS2_DBG "Contains %d blocks with total wasted size %u, average wasted size: %u\n",
371 			numblocks, dirty, dirty / numblocks);
372 	}
373 
374 	if (list_empty(&c->very_dirty_list)) {
375 		printk(JFFS2_DBG "very_dirty_list: empty\n");
376 	} else {
377 		struct list_head *this;
378 		int numblocks = 0;
379 		uint32_t dirty = 0;
380 
381 		list_for_each(this, &c->very_dirty_list) {
382 			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
383 
384 			numblocks ++;
385 			dirty += jeb->dirty_size;
386 			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
387 				printk(JFFS2_DBG "very_dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
388 					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
389 					jeb->unchecked_size, jeb->free_size);
390 			}
391 		}
392 
393 		printk (JFFS2_DBG "Contains %d blocks with total dirty size %u, average dirty size: %u\n",
394 			numblocks, dirty, dirty / numblocks);
395 	}
396 
397 	if (list_empty(&c->dirty_list)) {
398 		printk(JFFS2_DBG "dirty_list: empty\n");
399 	} else {
400 		struct list_head *this;
401 		int numblocks = 0;
402 		uint32_t dirty = 0;
403 
404 		list_for_each(this, &c->dirty_list) {
405 			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
406 
407 			numblocks ++;
408 			dirty += jeb->dirty_size;
409 			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
410 				printk(JFFS2_DBG "dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
411 					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
412 					jeb->unchecked_size, jeb->free_size);
413 			}
414 		}
415 
416 		printk (JFFS2_DBG "contains %d blocks with total dirty size %u, average dirty size: %u\n",
417 			numblocks, dirty, dirty / numblocks);
418 	}
419 
420 	if (list_empty(&c->erasable_list)) {
421 		printk(JFFS2_DBG "erasable_list: empty\n");
422 	} else {
423 		struct list_head *this;
424 
425 		list_for_each(this, &c->erasable_list) {
426 			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
427 
428 			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
429 				printk(JFFS2_DBG "erasable_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, 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 	if (list_empty(&c->erasing_list)) {
437 		printk(JFFS2_DBG "erasing_list: empty\n");
438 	} else {
439 		struct list_head *this;
440 
441 		list_for_each(this, &c->erasing_list) {
442 			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
443 
444 			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
445 				printk(JFFS2_DBG "erasing_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
446 					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
447 					jeb->unchecked_size, jeb->free_size);
448 			}
449 		}
450 	}
451 
452 	if (list_empty(&c->erase_pending_list)) {
453 		printk(JFFS2_DBG "erase_pending_list: empty\n");
454 	} else {
455 		struct list_head *this;
456 
457 		list_for_each(this, &c->erase_pending_list) {
458 			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
459 
460 			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
461 				printk(JFFS2_DBG "erase_pending_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
462 					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
463 					jeb->unchecked_size, jeb->free_size);
464 			}
465 		}
466 	}
467 
468 	if (list_empty(&c->erasable_pending_wbuf_list)) {
469 		printk(JFFS2_DBG "erasable_pending_wbuf_list: empty\n");
470 	} else {
471 		struct list_head *this;
472 
473 		list_for_each(this, &c->erasable_pending_wbuf_list) {
474 			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
475 
476 			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
477 				printk(JFFS2_DBG "erasable_pending_wbuf_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
478 					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
479 					jeb->unchecked_size, jeb->free_size);
480 			}
481 		}
482 	}
483 
484 	if (list_empty(&c->free_list)) {
485 		printk(JFFS2_DBG "free_list: empty\n");
486 	} else {
487 		struct list_head *this;
488 
489 		list_for_each(this, &c->free_list) {
490 			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
491 
492 			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
493 				printk(JFFS2_DBG "free_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
494 					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
495 					jeb->unchecked_size, jeb->free_size);
496 			}
497 		}
498 	}
499 
500 	if (list_empty(&c->bad_list)) {
501 		printk(JFFS2_DBG "bad_list: empty\n");
502 	} else {
503 		struct list_head *this;
504 
505 		list_for_each(this, &c->bad_list) {
506 			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
507 
508 			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
509 				printk(JFFS2_DBG "bad_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
510 					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
511 					jeb->unchecked_size, jeb->free_size);
512 			}
513 		}
514 	}
515 
516 	if (list_empty(&c->bad_used_list)) {
517 		printk(JFFS2_DBG "bad_used_list: empty\n");
518 	} else {
519 		struct list_head *this;
520 
521 		list_for_each(this, &c->bad_used_list) {
522 			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
523 
524 			if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
525 				printk(JFFS2_DBG "bad_used_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
526 					jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
527 					jeb->unchecked_size, jeb->free_size);
528 			}
529 		}
530 	}
531 }
532 
533 void
534 __jffs2_dbg_dump_fragtree(struct jffs2_inode_info *f)
535 {
536 	down(&f->sem);
537 	jffs2_dbg_dump_fragtree_nolock(f);
538 	up(&f->sem);
539 }
540 
541 void
542 __jffs2_dbg_dump_fragtree_nolock(struct jffs2_inode_info *f)
543 {
544 	struct jffs2_node_frag *this = frag_first(&f->fragtree);
545 	uint32_t lastofs = 0;
546 	int buggy = 0;
547 
548 	printk(JFFS2_DBG_MSG_PREFIX " dump fragtree of ino #%u\n", f->inocache->ino);
549 	while(this) {
550 		if (this->node)
551 			printk(JFFS2_DBG "frag %#04x-%#04x: %#08x(%d) on flash (*%p), left (%p), right (%p), parent (%p)\n",
552 				this->ofs, this->ofs+this->size, ref_offset(this->node->raw),
553 				ref_flags(this->node->raw), this, frag_left(this), frag_right(this),
554 				frag_parent(this));
555 		else
556 			printk(JFFS2_DBG "frag %#04x-%#04x: hole (*%p). left (%p), right (%p), parent (%p)\n",
557 				this->ofs, this->ofs+this->size, this, frag_left(this),
558 				frag_right(this), frag_parent(this));
559 		if (this->ofs != lastofs)
560 			buggy = 1;
561 		lastofs = this->ofs + this->size;
562 		this = frag_next(this);
563 	}
564 
565 	if (f->metadata)
566 		printk(JFFS2_DBG "metadata at 0x%08x\n", ref_offset(f->metadata->raw));
567 
568 	if (buggy) {
569 		JFFS2_ERROR("frag tree got a hole in it.\n");
570 		BUG();
571 	}
572 }
573 
574 #define JFFS2_BUFDUMP_BYTES_PER_LINE	32
575 void
576 __jffs2_dbg_dump_buffer(unsigned char *buf, int len, uint32_t offs)
577 {
578 	int skip;
579 	int i;
580 
581 	printk(JFFS2_DBG_MSG_PREFIX " dump from offset %#08x to offset %#08x (%x bytes).\n",
582 		offs, offs + len, len);
583 	i = skip = offs % JFFS2_BUFDUMP_BYTES_PER_LINE;
584 	offs = offs & ~(JFFS2_BUFDUMP_BYTES_PER_LINE - 1);
585 
586 	if (skip != 0)
587 		printk(JFFS2_DBG "%#08x: ", offs);
588 
589 	while (skip--)
590 		printk("   ");
591 
592 	while (i < len) {
593 		if ((i % JFFS2_BUFDUMP_BYTES_PER_LINE) == 0 && i != len -1) {
594 			if (i != 0)
595 				printk("\n");
596 			offs += JFFS2_BUFDUMP_BYTES_PER_LINE;
597 			printk(JFFS2_DBG "%0#8x: ", offs);
598 		}
599 
600 		printk("%02x ", buf[i]);
601 
602 		i += 1;
603 	}
604 
605 	printk("\n");
606 }
607 
608 /*
609  * Dump a JFFS2 node.
610  */
611 void
612 __jffs2_dbg_dump_node(struct jffs2_sb_info *c, uint32_t ofs)
613 {
614 	union jffs2_node_union node;
615 	int len = sizeof(union jffs2_node_union);
616 	size_t retlen;
617 	uint32_t crc;
618 	int ret;
619 
620 	printk(JFFS2_DBG_MSG_PREFIX " dump node at offset %#08x.\n", ofs);
621 
622 	ret = jffs2_flash_read(c, ofs, len, &retlen, (unsigned char *)&node);
623 	if (ret || (retlen != len)) {
624 		JFFS2_ERROR("read %d bytes failed or short. ret %d, retlen %zd.\n",
625 			len, ret, retlen);
626 		return;
627 	}
628 
629 	printk(JFFS2_DBG "magic:\t%#04x\n", je16_to_cpu(node.u.magic));
630 	printk(JFFS2_DBG "nodetype:\t%#04x\n", je16_to_cpu(node.u.nodetype));
631 	printk(JFFS2_DBG "totlen:\t%#08x\n", je32_to_cpu(node.u.totlen));
632 	printk(JFFS2_DBG "hdr_crc:\t%#08x\n", je32_to_cpu(node.u.hdr_crc));
633 
634 	crc = crc32(0, &node.u, sizeof(node.u) - 4);
635 	if (crc != je32_to_cpu(node.u.hdr_crc)) {
636 		JFFS2_ERROR("wrong common header CRC.\n");
637 		return;
638 	}
639 
640 	if (je16_to_cpu(node.u.magic) != JFFS2_MAGIC_BITMASK &&
641 		je16_to_cpu(node.u.magic) != JFFS2_OLD_MAGIC_BITMASK)
642 	{
643 		JFFS2_ERROR("wrong node magic: %#04x instead of %#04x.\n",
644 			je16_to_cpu(node.u.magic), JFFS2_MAGIC_BITMASK);
645 		return;
646 	}
647 
648 	switch(je16_to_cpu(node.u.nodetype)) {
649 
650 	case JFFS2_NODETYPE_INODE:
651 
652 		printk(JFFS2_DBG "the node is inode node\n");
653 		printk(JFFS2_DBG "ino:\t%#08x\n", je32_to_cpu(node.i.ino));
654 		printk(JFFS2_DBG "version:\t%#08x\n", je32_to_cpu(node.i.version));
655 		printk(JFFS2_DBG "mode:\t%#08x\n", node.i.mode.m);
656 		printk(JFFS2_DBG "uid:\t%#04x\n", je16_to_cpu(node.i.uid));
657 		printk(JFFS2_DBG "gid:\t%#04x\n", je16_to_cpu(node.i.gid));
658 		printk(JFFS2_DBG "isize:\t%#08x\n", je32_to_cpu(node.i.isize));
659 		printk(JFFS2_DBG "atime:\t%#08x\n", je32_to_cpu(node.i.atime));
660 		printk(JFFS2_DBG "mtime:\t%#08x\n", je32_to_cpu(node.i.mtime));
661 		printk(JFFS2_DBG "ctime:\t%#08x\n", je32_to_cpu(node.i.ctime));
662 		printk(JFFS2_DBG "offset:\t%#08x\n", je32_to_cpu(node.i.offset));
663 		printk(JFFS2_DBG "csize:\t%#08x\n", je32_to_cpu(node.i.csize));
664 		printk(JFFS2_DBG "dsize:\t%#08x\n", je32_to_cpu(node.i.dsize));
665 		printk(JFFS2_DBG "compr:\t%#02x\n", node.i.compr);
666 		printk(JFFS2_DBG "usercompr:\t%#02x\n", node.i.usercompr);
667 		printk(JFFS2_DBG "flags:\t%#04x\n", je16_to_cpu(node.i.flags));
668 		printk(JFFS2_DBG "data_crc:\t%#08x\n", je32_to_cpu(node.i.data_crc));
669 		printk(JFFS2_DBG "node_crc:\t%#08x\n", je32_to_cpu(node.i.node_crc));
670 
671 		crc = crc32(0, &node.i, sizeof(node.i) - 8);
672 		if (crc != je32_to_cpu(node.i.node_crc)) {
673 			JFFS2_ERROR("wrong node header CRC.\n");
674 			return;
675 		}
676 		break;
677 
678 	case JFFS2_NODETYPE_DIRENT:
679 
680 		printk(JFFS2_DBG "the node is dirent node\n");
681 		printk(JFFS2_DBG "pino:\t%#08x\n", je32_to_cpu(node.d.pino));
682 		printk(JFFS2_DBG "version:\t%#08x\n", je32_to_cpu(node.d.version));
683 		printk(JFFS2_DBG "ino:\t%#08x\n", je32_to_cpu(node.d.ino));
684 		printk(JFFS2_DBG "mctime:\t%#08x\n", je32_to_cpu(node.d.mctime));
685 		printk(JFFS2_DBG "nsize:\t%#02x\n", node.d.nsize);
686 		printk(JFFS2_DBG "type:\t%#02x\n", node.d.type);
687 		printk(JFFS2_DBG "node_crc:\t%#08x\n", je32_to_cpu(node.d.node_crc));
688 		printk(JFFS2_DBG "name_crc:\t%#08x\n", je32_to_cpu(node.d.name_crc));
689 
690 		node.d.name[node.d.nsize] = '\0';
691 		printk(JFFS2_DBG "name:\t\"%s\"\n", node.d.name);
692 
693 		crc = crc32(0, &node.d, sizeof(node.d) - 8);
694 		if (crc != je32_to_cpu(node.d.node_crc)) {
695 			JFFS2_ERROR("wrong node header CRC.\n");
696 			return;
697 		}
698 		break;
699 
700 	default:
701 		printk(JFFS2_DBG "node type is unknown\n");
702 		break;
703 	}
704 }
705 #endif /* JFFS2_DBG_DUMPS || JFFS2_DBG_PARANOIA_CHECKS */
706