1/* 2 * JFFS2 -- Journalling Flash File System, Version 2. 3 * 4 * Copyright �� 2001-2007 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 */ 11 12#include <linux/kernel.h> 13#include <linux/types.h> 14#include <linux/pagemap.h> 15#include <linux/crc32.h> 16#include <linux/jffs2.h> 17#include <linux/mtd/mtd.h> 18#include "nodelist.h" 19#include "debug.h" 20 21#ifdef JFFS2_DBG_SANITY_CHECKS 22 23void 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 47void 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 */ 62void 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 70void 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 */ 120void 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 */ 159void 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 168void 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 (ref_offset(ref2) < jeb->offset || 181 ref_offset(ref2) > 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 ((!ref_next(ref2)) != (ref2 == jeb->last_node)) { 195 JFFS2_ERROR("node_ref for node at %#08x (mem %p) has next at %#08x (mem %p), last_node is at %#08x (mem %p).\n", 196 ref_offset(ref2), ref2, ref_offset(ref_next(ref2)), ref_next(ref2), 197 ref_offset(jeb->last_node), jeb->last_node); 198 goto error; 199 } 200 ref2 = ref_next(ref2); 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 216 return; 217 218error: 219 __jffs2_dbg_dump_node_refs_nolock(c, jeb); 220 __jffs2_dbg_dump_jeb_nolock(jeb); 221 __jffs2_dbg_dump_block_lists_nolock(c); 222 BUG(); 223 224} 225#endif /* JFFS2_DBG_PARANOIA_CHECKS */ 226 227#if defined(JFFS2_DBG_DUMPS) || defined(JFFS2_DBG_PARANOIA_CHECKS) 228/* 229 * Dump the node_refs of the 'jeb' JFFS2 eraseblock. 230 */ 231void 232__jffs2_dbg_dump_node_refs(struct jffs2_sb_info *c, 233 struct jffs2_eraseblock *jeb) 234{ 235 spin_lock(&c->erase_completion_lock); 236 __jffs2_dbg_dump_node_refs_nolock(c, jeb); 237 spin_unlock(&c->erase_completion_lock); 238} 239 240void 241__jffs2_dbg_dump_node_refs_nolock(struct jffs2_sb_info *c, 242 struct jffs2_eraseblock *jeb) 243{ 244 struct jffs2_raw_node_ref *ref; 245 int i = 0; 246 247 printk(JFFS2_DBG_MSG_PREFIX " Dump node_refs of the eraseblock %#08x\n", jeb->offset); 248 if (!jeb->first_node) { 249 printk(JFFS2_DBG_MSG_PREFIX " no nodes in the eraseblock %#08x\n", jeb->offset); 250 return; 251 } 252 253 printk(JFFS2_DBG); 254 for (ref = jeb->first_node; ; ref = ref_next(ref)) { 255 printk("%#08x(%#x)", ref_offset(ref), ref->__totlen); 256 if (ref_next(ref)) 257 printk("->"); 258 else 259 break; 260 if (++i == 4) { 261 i = 0; 262 printk("\n" JFFS2_DBG); 263 } 264 } 265 printk("\n"); 266} 267 268/* 269 * Dump an eraseblock's space accounting. 270 */ 271void 272__jffs2_dbg_dump_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) 273{ 274 spin_lock(&c->erase_completion_lock); 275 __jffs2_dbg_dump_jeb_nolock(jeb); 276 spin_unlock(&c->erase_completion_lock); 277} 278 279void 280__jffs2_dbg_dump_jeb_nolock(struct jffs2_eraseblock *jeb) 281{ 282 if (!jeb) 283 return; 284 285 printk(JFFS2_DBG_MSG_PREFIX " dump space accounting for the eraseblock at %#08x:\n", 286 jeb->offset); 287 288 printk(JFFS2_DBG "used_size: %#08x\n", jeb->used_size); 289 printk(JFFS2_DBG "dirty_size: %#08x\n", jeb->dirty_size); 290 printk(JFFS2_DBG "wasted_size: %#08x\n", jeb->wasted_size); 291 printk(JFFS2_DBG "unchecked_size: %#08x\n", jeb->unchecked_size); 292 printk(JFFS2_DBG "free_size: %#08x\n", jeb->free_size); 293} 294 295void 296__jffs2_dbg_dump_block_lists(struct jffs2_sb_info *c) 297{ 298 spin_lock(&c->erase_completion_lock); 299 __jffs2_dbg_dump_block_lists_nolock(c); 300 spin_unlock(&c->erase_completion_lock); 301} 302 303void 304__jffs2_dbg_dump_block_lists_nolock(struct jffs2_sb_info *c) 305{ 306 printk(JFFS2_DBG_MSG_PREFIX " dump JFFS2 blocks lists:\n"); 307 308 printk(JFFS2_DBG "flash_size: %#08x\n", c->flash_size); 309 printk(JFFS2_DBG "used_size: %#08x\n", c->used_size); 310 printk(JFFS2_DBG "dirty_size: %#08x\n", c->dirty_size); 311 printk(JFFS2_DBG "wasted_size: %#08x\n", c->wasted_size); 312 printk(JFFS2_DBG "unchecked_size: %#08x\n", c->unchecked_size); 313 printk(JFFS2_DBG "free_size: %#08x\n", c->free_size); 314 printk(JFFS2_DBG "erasing_size: %#08x\n", c->erasing_size); 315 printk(JFFS2_DBG "bad_size: %#08x\n", c->bad_size); 316 printk(JFFS2_DBG "sector_size: %#08x\n", c->sector_size); 317 printk(JFFS2_DBG "jffs2_reserved_blocks size: %#08x\n", 318 c->sector_size * c->resv_blocks_write); 319 320 if (c->nextblock) 321 printk(JFFS2_DBG "nextblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 322 c->nextblock->offset, c->nextblock->used_size, 323 c->nextblock->dirty_size, c->nextblock->wasted_size, 324 c->nextblock->unchecked_size, c->nextblock->free_size); 325 else 326 printk(JFFS2_DBG "nextblock: NULL\n"); 327 328 if (c->gcblock) 329 printk(JFFS2_DBG "gcblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 330 c->gcblock->offset, c->gcblock->used_size, c->gcblock->dirty_size, 331 c->gcblock->wasted_size, c->gcblock->unchecked_size, c->gcblock->free_size); 332 else 333 printk(JFFS2_DBG "gcblock: NULL\n"); 334 335 if (list_empty(&c->clean_list)) { 336 printk(JFFS2_DBG "clean_list: empty\n"); 337 } else { 338 struct list_head *this; 339 int numblocks = 0; 340 uint32_t dirty = 0; 341 342 list_for_each(this, &c->clean_list) { 343 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 344 numblocks ++; 345 dirty += jeb->wasted_size; 346 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 347 printk(JFFS2_DBG "clean_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 348 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 349 jeb->unchecked_size, jeb->free_size); 350 } 351 } 352 353 printk (JFFS2_DBG "Contains %d blocks with total wasted size %u, average wasted size: %u\n", 354 numblocks, dirty, dirty / numblocks); 355 } 356 357 if (list_empty(&c->very_dirty_list)) { 358 printk(JFFS2_DBG "very_dirty_list: empty\n"); 359 } else { 360 struct list_head *this; 361 int numblocks = 0; 362 uint32_t dirty = 0; 363 364 list_for_each(this, &c->very_dirty_list) { 365 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 366 367 numblocks ++; 368 dirty += jeb->dirty_size; 369 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 370 printk(JFFS2_DBG "very_dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 371 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 372 jeb->unchecked_size, jeb->free_size); 373 } 374 } 375 376 printk (JFFS2_DBG "Contains %d blocks with total dirty size %u, average dirty size: %u\n", 377 numblocks, dirty, dirty / numblocks); 378 } 379 380 if (list_empty(&c->dirty_list)) { 381 printk(JFFS2_DBG "dirty_list: empty\n"); 382 } else { 383 struct list_head *this; 384 int numblocks = 0; 385 uint32_t dirty = 0; 386 387 list_for_each(this, &c->dirty_list) { 388 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 389 390 numblocks ++; 391 dirty += jeb->dirty_size; 392 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 393 printk(JFFS2_DBG "dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 394 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 395 jeb->unchecked_size, jeb->free_size); 396 } 397 } 398 399 printk (JFFS2_DBG "contains %d blocks with total dirty size %u, average dirty size: %u\n", 400 numblocks, dirty, dirty / numblocks); 401 } 402 403 if (list_empty(&c->erasable_list)) { 404 printk(JFFS2_DBG "erasable_list: empty\n"); 405 } else { 406 struct list_head *this; 407 408 list_for_each(this, &c->erasable_list) { 409 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 410 411 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 412 printk(JFFS2_DBG "erasable_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 413 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 414 jeb->unchecked_size, jeb->free_size); 415 } 416 } 417 } 418 419 if (list_empty(&c->erasing_list)) { 420 printk(JFFS2_DBG "erasing_list: empty\n"); 421 } else { 422 struct list_head *this; 423 424 list_for_each(this, &c->erasing_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 "erasing_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->erase_pending_list)) { 436 printk(JFFS2_DBG "erase_pending_list: empty\n"); 437 } else { 438 struct list_head *this; 439 440 list_for_each(this, &c->erase_pending_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 "erase_pending_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->erasable_pending_wbuf_list)) { 452 printk(JFFS2_DBG "erasable_pending_wbuf_list: empty\n"); 453 } else { 454 struct list_head *this; 455 456 list_for_each(this, &c->erasable_pending_wbuf_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 "erasable_pending_wbuf_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->free_list)) { 468 printk(JFFS2_DBG "free_list: empty\n"); 469 } else { 470 struct list_head *this; 471 472 list_for_each(this, &c->free_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 "free_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->bad_list)) { 484 printk(JFFS2_DBG "bad_list: empty\n"); 485 } else { 486 struct list_head *this; 487 488 list_for_each(this, &c->bad_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 "bad_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_used_list)) { 500 printk(JFFS2_DBG "bad_used_list: empty\n"); 501 } else { 502 struct list_head *this; 503 504 list_for_each(this, &c->bad_used_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_used_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 516void 517__jffs2_dbg_dump_fragtree(struct jffs2_inode_info *f) 518{ 519 down(&f->sem); 520 jffs2_dbg_dump_fragtree_nolock(f); 521 up(&f->sem); 522} 523 524void 525__jffs2_dbg_dump_fragtree_nolock(struct jffs2_inode_info *f) 526{ 527 struct jffs2_node_frag *this = frag_first(&f->fragtree); 528 uint32_t lastofs = 0; 529 int buggy = 0; 530 531 printk(JFFS2_DBG_MSG_PREFIX " dump fragtree of ino #%u\n", f->inocache->ino); 532 while(this) { 533 if (this->node) 534 printk(JFFS2_DBG "frag %#04x-%#04x: %#08x(%d) on flash (*%p), left (%p), right (%p), parent (%p)\n", 535 this->ofs, this->ofs+this->size, ref_offset(this->node->raw), 536 ref_flags(this->node->raw), this, frag_left(this), frag_right(this), 537 frag_parent(this)); 538 else 539 printk(JFFS2_DBG "frag %#04x-%#04x: hole (*%p). left (%p), right (%p), parent (%p)\n", 540 this->ofs, this->ofs+this->size, this, frag_left(this), 541 frag_right(this), frag_parent(this)); 542 if (this->ofs != lastofs) 543 buggy = 1; 544 lastofs = this->ofs + this->size; 545 this = frag_next(this); 546 } 547 548 if (f->metadata) 549 printk(JFFS2_DBG "metadata at 0x%08x\n", ref_offset(f->metadata->raw)); 550 551 if (buggy) { 552 JFFS2_ERROR("frag tree got a hole in it.\n"); 553 BUG(); 554 } 555} 556 557#define JFFS2_BUFDUMP_BYTES_PER_LINE 32 558void 559__jffs2_dbg_dump_buffer(unsigned char *buf, int len, uint32_t offs) 560{ 561 int skip; 562 int i; 563 564 printk(JFFS2_DBG_MSG_PREFIX " dump from offset %#08x to offset %#08x (%x bytes).\n", 565 offs, offs + len, len); 566 i = skip = offs % JFFS2_BUFDUMP_BYTES_PER_LINE; 567 offs = offs & ~(JFFS2_BUFDUMP_BYTES_PER_LINE - 1); 568 569 if (skip != 0) 570 printk(JFFS2_DBG "%#08x: ", offs); 571 572 while (skip--) 573 printk(" "); 574 575 while (i < len) { 576 if ((i % JFFS2_BUFDUMP_BYTES_PER_LINE) == 0 && i != len -1) { 577 if (i != 0) 578 printk("\n"); 579 offs += JFFS2_BUFDUMP_BYTES_PER_LINE; 580 printk(JFFS2_DBG "%0#8x: ", offs); 581 } 582 583 printk("%02x ", buf[i]); 584 585 i += 1; 586 } 587 588 printk("\n"); 589} 590 591/* 592 * Dump a JFFS2 node. 593 */ 594void 595__jffs2_dbg_dump_node(struct jffs2_sb_info *c, uint32_t ofs) 596{ 597 union jffs2_node_union node; 598 int len = sizeof(union jffs2_node_union); 599 size_t retlen; 600 uint32_t crc; 601 int ret; 602 603 printk(JFFS2_DBG_MSG_PREFIX " dump node at offset %#08x.\n", ofs); 604 605 ret = jffs2_flash_read(c, ofs, len, &retlen, (unsigned char *)&node); 606 if (ret || (retlen != len)) { 607 JFFS2_ERROR("read %d bytes failed or short. ret %d, retlen %zd.\n", 608 len, ret, retlen); 609 return; 610 } 611 612 printk(JFFS2_DBG "magic:\t%#04x\n", je16_to_cpu(node.u.magic)); 613 printk(JFFS2_DBG "nodetype:\t%#04x\n", je16_to_cpu(node.u.nodetype)); 614 printk(JFFS2_DBG "totlen:\t%#08x\n", je32_to_cpu(node.u.totlen)); 615 printk(JFFS2_DBG "hdr_crc:\t%#08x\n", je32_to_cpu(node.u.hdr_crc)); 616 617 crc = crc32(0, &node.u, sizeof(node.u) - 4); 618 if (crc != je32_to_cpu(node.u.hdr_crc)) { 619 JFFS2_ERROR("wrong common header CRC.\n"); 620 return; 621 } 622 623 if (je16_to_cpu(node.u.magic) != JFFS2_MAGIC_BITMASK && 624 je16_to_cpu(node.u.magic) != JFFS2_OLD_MAGIC_BITMASK) 625 { 626 JFFS2_ERROR("wrong node magic: %#04x instead of %#04x.\n", 627 je16_to_cpu(node.u.magic), JFFS2_MAGIC_BITMASK); 628 return; 629 } 630 631 switch(je16_to_cpu(node.u.nodetype)) { 632 633 case JFFS2_NODETYPE_INODE: 634 635 printk(JFFS2_DBG "the node is inode node\n"); 636 printk(JFFS2_DBG "ino:\t%#08x\n", je32_to_cpu(node.i.ino)); 637 printk(JFFS2_DBG "version:\t%#08x\n", je32_to_cpu(node.i.version)); 638 printk(JFFS2_DBG "mode:\t%#08x\n", node.i.mode.m); 639 printk(JFFS2_DBG "uid:\t%#04x\n", je16_to_cpu(node.i.uid)); 640 printk(JFFS2_DBG "gid:\t%#04x\n", je16_to_cpu(node.i.gid)); 641 printk(JFFS2_DBG "isize:\t%#08x\n", je32_to_cpu(node.i.isize)); 642 printk(JFFS2_DBG "atime:\t%#08x\n", je32_to_cpu(node.i.atime)); 643 printk(JFFS2_DBG "mtime:\t%#08x\n", je32_to_cpu(node.i.mtime)); 644 printk(JFFS2_DBG "ctime:\t%#08x\n", je32_to_cpu(node.i.ctime)); 645 printk(JFFS2_DBG "offset:\t%#08x\n", je32_to_cpu(node.i.offset)); 646 printk(JFFS2_DBG "csize:\t%#08x\n", je32_to_cpu(node.i.csize)); 647 printk(JFFS2_DBG "dsize:\t%#08x\n", je32_to_cpu(node.i.dsize)); 648 printk(JFFS2_DBG "compr:\t%#02x\n", node.i.compr); 649 printk(JFFS2_DBG "usercompr:\t%#02x\n", node.i.usercompr); 650 printk(JFFS2_DBG "flags:\t%#04x\n", je16_to_cpu(node.i.flags)); 651 printk(JFFS2_DBG "data_crc:\t%#08x\n", je32_to_cpu(node.i.data_crc)); 652 printk(JFFS2_DBG "node_crc:\t%#08x\n", je32_to_cpu(node.i.node_crc)); 653 654 crc = crc32(0, &node.i, sizeof(node.i) - 8); 655 if (crc != je32_to_cpu(node.i.node_crc)) { 656 JFFS2_ERROR("wrong node header CRC.\n"); 657 return; 658 } 659 break; 660 661 case JFFS2_NODETYPE_DIRENT: 662 663 printk(JFFS2_DBG "the node is dirent node\n"); 664 printk(JFFS2_DBG "pino:\t%#08x\n", je32_to_cpu(node.d.pino)); 665 printk(JFFS2_DBG "version:\t%#08x\n", je32_to_cpu(node.d.version)); 666 printk(JFFS2_DBG "ino:\t%#08x\n", je32_to_cpu(node.d.ino)); 667 printk(JFFS2_DBG "mctime:\t%#08x\n", je32_to_cpu(node.d.mctime)); 668 printk(JFFS2_DBG "nsize:\t%#02x\n", node.d.nsize); 669 printk(JFFS2_DBG "type:\t%#02x\n", node.d.type); 670 printk(JFFS2_DBG "node_crc:\t%#08x\n", je32_to_cpu(node.d.node_crc)); 671 printk(JFFS2_DBG "name_crc:\t%#08x\n", je32_to_cpu(node.d.name_crc)); 672 673 node.d.name[node.d.nsize] = '\0'; 674 printk(JFFS2_DBG "name:\t\"%s\"\n", node.d.name); 675 676 crc = crc32(0, &node.d, sizeof(node.d) - 8); 677 if (crc != je32_to_cpu(node.d.node_crc)) { 678 JFFS2_ERROR("wrong node header CRC.\n"); 679 return; 680 } 681 break; 682 683 default: 684 printk(JFFS2_DBG "node type is unknown\n"); 685 break; 686 } 687} 688#endif /* JFFS2_DBG_DUMPS || JFFS2_DBG_PARANOIA_CHECKS */ 689