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