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