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