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