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 */ 711