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.1 2005/07/17 06:56:20 dedekind Exp $ 11 * 12 */ 13 #include <linux/kernel.h> 14 #include <linux/pagemap.h> 15 #include "nodelist.h" 16 #include "debug.h" 17 18 #ifdef JFFS2_DBG_PARANOIA_CHECKS 19 20 void 21 jffs2_dbg_fragtree_paranoia_check(struct jffs2_inode_info *f) 22 { 23 struct jffs2_node_frag *frag; 24 int bitched = 0; 25 26 for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) { 27 struct jffs2_full_dnode *fn = frag->node; 28 29 if (!fn || !fn->raw) 30 continue; 31 32 if (ref_flags(fn->raw) == REF_PRISTINE) { 33 if (fn->frags > 1) { 34 printk(KERN_ERR "REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2\n", 35 ref_offset(fn->raw), fn->frags); 36 bitched = 1; 37 } 38 39 /* A hole node which isn't multi-page should be garbage-collected 40 and merged anyway, so we just check for the frag size here, 41 rather than mucking around with actually reading the node 42 and checking the compression type, which is the real way 43 to tell a hole node. */ 44 if (frag->ofs & (PAGE_CACHE_SIZE-1) && frag_prev(frag) 45 && frag_prev(frag)->size < PAGE_CACHE_SIZE && frag_prev(frag)->node) { 46 printk(KERN_ERR "REF_PRISTINE node at 0x%08x had a previous non-hole frag " 47 "in the same page. Tell dwmw2\n", ref_offset(fn->raw)); 48 bitched = 1; 49 } 50 51 if ((frag->ofs+frag->size) & (PAGE_CACHE_SIZE-1) && frag_next(frag) 52 && frag_next(frag)->size < PAGE_CACHE_SIZE && frag_next(frag)->node) { 53 printk(KERN_ERR "REF_PRISTINE node at 0x%08x (%08x-%08x) had a following " 54 "non-hole frag in the same page. Tell dwmw2\n", 55 ref_offset(fn->raw), frag->ofs, frag->ofs+frag->size); 56 bitched = 1; 57 } 58 } 59 } 60 61 if (bitched) { 62 printk(KERN_ERR "Fragtree is corrupted. Fragtree dump:\n"); 63 jffs2_dbg_dump_fragtree(f); 64 BUG(); 65 } 66 } 67 68 /* 69 * Check if the flash contains all 0xFF before we start writing. 70 */ 71 void 72 jffs2_dbg_prewrite_paranoia_check(struct jffs2_sb_info *c, uint32_t ofs, int len) 73 { 74 size_t retlen; 75 int ret, i; 76 unsigned char *buf; 77 78 buf = kmalloc(len, GFP_KERNEL); 79 if (!buf) 80 return; 81 82 ret = jffs2_flash_read(c, ofs, len, &retlen, buf); 83 if (ret || (retlen != len)) { 84 printk(KERN_WARNING "read %d bytes failed or short in %s(). ret %d, retlen %zd\n", 85 len, __FUNCTION__, ret, retlen); 86 kfree(buf); 87 return; 88 } 89 90 ret = 0; 91 for (i = 0; i < len; i++) 92 if (buf[i] != 0xff) 93 ret = 1; 94 95 if (ret) { 96 printk(KERN_ERR "ARGH. About to write node to %#08x on flash, but there are data " 97 "already there. The first corrupted byte is at %#08x.\n", ofs, ofs + i); 98 jffs2_dbg_dump_buffer(buf, len, ofs); 99 kfree(buf); 100 BUG(); 101 } 102 103 kfree(buf); 104 } 105 106 /* 107 * Check the space accounting and node_ref list correctness for the JFFS2 erasable block 'jeb'. 108 */ 109 void 110 jffs2_dbg_acct_paranoia_check(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) 111 { 112 uint32_t my_used_size = 0; 113 uint32_t my_unchecked_size = 0; 114 uint32_t my_dirty_size = 0; 115 struct jffs2_raw_node_ref *ref2 = jeb->first_node; 116 117 while (ref2) { 118 uint32_t totlen = ref_totlen(c, jeb, ref2); 119 120 if (ref2->flash_offset < jeb->offset || 121 ref2->flash_offset > jeb->offset + c->sector_size) { 122 printk(KERN_ERR "node_ref %#08x shouldn't be in block at %#08x!\n", 123 ref_offset(ref2), jeb->offset); 124 jffs2_dbg_dump_node_refs(c, jeb); 125 jffs2_dbg_dump_block_lists(c); 126 BUG(); 127 128 } 129 if (ref_flags(ref2) == REF_UNCHECKED) 130 my_unchecked_size += totlen; 131 else if (!ref_obsolete(ref2)) 132 my_used_size += totlen; 133 else 134 my_dirty_size += totlen; 135 136 if ((!ref2->next_phys) != (ref2 == jeb->last_node)) { 137 printk(KERN_ERR "node_ref for node at %#08x (mem %p) has next_phys at %#08x (mem %p), " 138 "last_node is at %#08x (mem %p)\n", 139 ref_offset(ref2), ref2, ref_offset(ref2->next_phys), ref2->next_phys, 140 ref_offset(jeb->last_node), jeb->last_node); 141 jffs2_dbg_dump_node_refs(c, jeb); 142 jffs2_dbg_dump_block_lists(c); 143 BUG(); 144 } 145 ref2 = ref2->next_phys; 146 } 147 148 if (my_used_size != jeb->used_size) { 149 printk(KERN_ERR "Calculated used size %#08x != stored used size %#08x\n", 150 my_used_size, jeb->used_size); 151 jffs2_dbg_dump_node_refs(c, jeb); 152 jffs2_dbg_dump_block_lists(c); 153 BUG(); 154 } 155 156 if (my_unchecked_size != jeb->unchecked_size) { 157 printk(KERN_ERR "Calculated unchecked size %#08x != stored unchecked size %#08x\n", 158 my_unchecked_size, jeb->unchecked_size); 159 jffs2_dbg_dump_node_refs(c, jeb); 160 jffs2_dbg_dump_block_lists(c); 161 BUG(); 162 } 163 164 if (my_dirty_size != jeb->dirty_size + jeb->wasted_size) { 165 printk(KERN_ERR "Calculated dirty+wasted size %#08x != stored dirty + wasted size %#08x\n", 166 my_dirty_size, jeb->dirty_size + jeb->wasted_size); 167 jffs2_dbg_dump_node_refs(c, jeb); 168 jffs2_dbg_dump_block_lists(c); 169 BUG(); 170 } 171 172 if (jeb->free_size == 0 173 && my_used_size + my_unchecked_size + my_dirty_size != c->sector_size) { 174 printk(KERN_ERR "The sum of all nodes in block (%#x) != size of block (%#x)\n", 175 my_used_size + my_unchecked_size + my_dirty_size, 176 c->sector_size); 177 jffs2_dbg_dump_node_refs(c, jeb); 178 jffs2_dbg_dump_block_lists(c); 179 BUG(); 180 } 181 } 182 #endif /* JFFS2_PARANOIA_CHECKS */ 183 184 #if defined(JFFS2_PARANOIA_CHECKS) || (CONFIG_JFFS2_FS_DEBUG > 0) 185 /* 186 * Dump the node_refs of the 'jeb' JFFS2 eraseblock. 187 */ 188 void 189 jffs2_dbg_dump_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) 190 { 191 struct jffs2_raw_node_ref *ref; 192 int i = 0; 193 194 if (!jeb->first_node) { 195 printk(KERN_DEBUG "no nodes in block %#08x\n", jeb->offset); 196 return; 197 } 198 199 printk(KERN_DEBUG); 200 for (ref = jeb->first_node; ; ref = ref->next_phys) { 201 printk("%#08x(%#x)", ref_offset(ref), ref->__totlen); 202 if (ref->next_phys) 203 printk("->"); 204 else 205 break; 206 if (++i == 4) { 207 i = 0; 208 printk("\n" KERN_DEBUG); 209 } 210 } 211 printk("\n"); 212 } 213 214 void 215 jffs2_dbg_dump_block_lists(struct jffs2_sb_info *c) 216 { 217 printk(KERN_DEBUG "flash_size: %#08x\n", c->flash_size); 218 printk(KERN_DEBUG "used_size: %#08x\n", c->used_size); 219 printk(KERN_DEBUG "dirty_size: %#08x\n", c->dirty_size); 220 printk(KERN_DEBUG "wasted_size: %#08x\n", c->wasted_size); 221 printk(KERN_DEBUG "unchecked_size: %#08x\n", c->unchecked_size); 222 printk(KERN_DEBUG "free_size: %#08x\n", c->free_size); 223 printk(KERN_DEBUG "erasing_size: %#08x\n", c->erasing_size); 224 printk(KERN_DEBUG "bad_size: %#08x\n", c->bad_size); 225 printk(KERN_DEBUG "sector_size: %#08x\n", c->sector_size); 226 printk(KERN_DEBUG "jffs2_reserved_blocks size: %#08x\n", 227 c->sector_size * c->resv_blocks_write); 228 229 if (c->nextblock) 230 printk(KERN_DEBUG "nextblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, " 231 "unchecked %#08x, free %#08x)\n", 232 c->nextblock->offset, c->nextblock->used_size, 233 c->nextblock->dirty_size, c->nextblock->wasted_size, 234 c->nextblock->unchecked_size, c->nextblock->free_size); 235 else 236 printk(KERN_DEBUG "nextblock: NULL\n"); 237 238 if (c->gcblock) 239 printk(KERN_DEBUG "gcblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, " 240 "unchecked %#08x, free %#08x)\n", 241 c->gcblock->offset, c->gcblock->used_size, c->gcblock->dirty_size, 242 c->gcblock->wasted_size, c->gcblock->unchecked_size, c->gcblock->free_size); 243 else 244 printk(KERN_DEBUG "gcblock: NULL\n"); 245 246 if (list_empty(&c->clean_list)) { 247 printk(KERN_DEBUG "clean_list: empty\n"); 248 } else { 249 struct list_head *this; 250 int numblocks = 0; 251 uint32_t dirty = 0; 252 253 list_for_each(this, &c->clean_list) { 254 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 255 numblocks ++; 256 dirty += jeb->wasted_size; 257 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 258 printk(KERN_DEBUG "clean_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, " 259 "unchecked %#08x, free %#08x)\n", 260 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 261 jeb->unchecked_size, jeb->free_size); 262 } 263 } 264 265 printk (KERN_DEBUG "Contains %d blocks with total wasted size %u, average wasted size: %u\n", 266 numblocks, dirty, dirty / numblocks); 267 } 268 269 if (list_empty(&c->very_dirty_list)) { 270 printk(KERN_DEBUG "very_dirty_list: empty\n"); 271 } else { 272 struct list_head *this; 273 int numblocks = 0; 274 uint32_t dirty = 0; 275 276 list_for_each(this, &c->very_dirty_list) { 277 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 278 279 numblocks ++; 280 dirty += jeb->dirty_size; 281 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 282 printk(KERN_DEBUG "very_dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, " 283 "unchecked %#08x, free %#08x)\n", 284 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 285 jeb->unchecked_size, jeb->free_size); 286 } 287 } 288 289 printk (KERN_DEBUG "Contains %d blocks with total dirty size %u, average dirty size: %u\n", 290 numblocks, dirty, dirty / numblocks); 291 } 292 293 if (list_empty(&c->dirty_list)) { 294 printk(KERN_DEBUG "dirty_list: empty\n"); 295 } else { 296 struct list_head *this; 297 int numblocks = 0; 298 uint32_t dirty = 0; 299 300 list_for_each(this, &c->dirty_list) { 301 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 302 303 numblocks ++; 304 dirty += jeb->dirty_size; 305 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 306 printk(KERN_DEBUG "dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, " 307 "unchecked %#08x, free %#08x)\n", 308 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 309 jeb->unchecked_size, jeb->free_size); 310 } 311 } 312 313 printk (KERN_DEBUG "Contains %d blocks with total dirty size %u, average dirty size: %u\n", 314 numblocks, dirty, dirty / numblocks); 315 } 316 317 if (list_empty(&c->erasable_list)) { 318 printk(KERN_DEBUG "erasable_list: empty\n"); 319 } else { 320 struct list_head *this; 321 322 list_for_each(this, &c->erasable_list) { 323 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 324 325 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 326 printk(KERN_DEBUG "erasable_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, " 327 "unchecked %#08x, free %#08x)\n", 328 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 329 jeb->unchecked_size, jeb->free_size); 330 } 331 } 332 } 333 334 if (list_empty(&c->erasing_list)) { 335 printk(KERN_DEBUG "erasing_list: empty\n"); 336 } else { 337 struct list_head *this; 338 339 list_for_each(this, &c->erasing_list) { 340 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 341 342 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 343 printk(KERN_DEBUG "erasing_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, " 344 "unchecked %#08x, free %#08x)\n", 345 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 346 jeb->unchecked_size, jeb->free_size); 347 } 348 } 349 } 350 351 if (list_empty(&c->erase_pending_list)) { 352 printk(KERN_DEBUG "erase_pending_list: empty\n"); 353 } else { 354 struct list_head *this; 355 356 list_for_each(this, &c->erase_pending_list) { 357 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 358 359 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 360 printk(KERN_DEBUG "erase_pending_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, " 361 "unchecked %#08x, free %#08x)\n", 362 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 363 jeb->unchecked_size, jeb->free_size); 364 } 365 } 366 } 367 368 if (list_empty(&c->erasable_pending_wbuf_list)) { 369 printk(KERN_DEBUG "erasable_pending_wbuf_list: empty\n"); 370 } else { 371 struct list_head *this; 372 373 list_for_each(this, &c->erasable_pending_wbuf_list) { 374 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 375 376 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 377 printk(KERN_DEBUG "erasable_pending_wbuf_list: %#08x (used %#08x, dirty %#08x, " 378 "wasted %#08x, 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 385 if (list_empty(&c->free_list)) { 386 printk(KERN_DEBUG "free_list: empty\n"); 387 } else { 388 struct list_head *this; 389 390 list_for_each(this, &c->free_list) { 391 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 392 393 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 394 printk(KERN_DEBUG "free_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, " 395 "unchecked %#08x, free %#08x)\n", 396 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 397 jeb->unchecked_size, jeb->free_size); 398 } 399 } 400 } 401 402 if (list_empty(&c->bad_list)) { 403 printk(KERN_DEBUG "bad_list: empty\n"); 404 } else { 405 struct list_head *this; 406 407 list_for_each(this, &c->bad_list) { 408 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 409 410 if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 411 printk(KERN_DEBUG "bad_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, " 412 "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->bad_used_list)) { 420 printk(KERN_DEBUG "bad_used_list: empty\n"); 421 } else { 422 struct list_head *this; 423 424 list_for_each(this, &c->bad_used_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(KERN_DEBUG "bad_used_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, " 429 "unchecked %#08x, free %#08x)\n", 430 jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 431 jeb->unchecked_size, jeb->free_size); 432 } 433 } 434 } 435 } 436 437 void 438 jffs2_dbg_dump_fragtree(struct jffs2_inode_info *f) 439 { 440 struct jffs2_node_frag *this = frag_first(&f->fragtree); 441 uint32_t lastofs = 0; 442 int buggy = 0; 443 444 printk(KERN_DEBUG "inode is ino #%u\n", f->inocache->ino); 445 while(this) { 446 if (this->node) 447 printk(KERN_DEBUG "frag %#04x-%#04x: %#08x(%d) on flash (*%p), left (%p), " 448 "right (%p), parent (%p)\n", 449 this->ofs, this->ofs+this->size, ref_offset(this->node->raw), 450 ref_flags(this->node->raw), this, frag_left(this), frag_right(this), 451 frag_parent(this)); 452 else 453 printk(KERN_DEBUG "frag %#04x-%#04x: hole (*%p). left (%p), right (%p), parent (%p)\n", 454 this->ofs, this->ofs+this->size, this, frag_left(this), 455 frag_right(this), frag_parent(this)); 456 if (this->ofs != lastofs) 457 buggy = 1; 458 lastofs = this->ofs + this->size; 459 this = frag_next(this); 460 } 461 462 if (f->metadata) 463 printk(KERN_DEBUG "metadata at 0x%08x\n", ref_offset(f->metadata->raw)); 464 465 if (buggy) { 466 printk(KERN_ERR "Error! %s(): Frag tree got a hole in it\n", __FUNCTION__); 467 BUG(); 468 } 469 } 470 471 #define JFFS3_BUFDUMP_BYTES_PER_LINE 8 472 void 473 jffs2_dbg_dump_buffer(char *buf, int len, uint32_t offs) 474 { 475 int i = 0; 476 int skip = offs & ~(JFFS3_BUFDUMP_BYTES_PER_LINE - 1); 477 478 while (i < len) { 479 int j = 0; 480 481 printk(KERN_DEBUG "0x#x: \n"); 482 while (skip) { 483 printk(" "); 484 skip -= 1; 485 } 486 487 while (j < JFFS3_BUFDUMP_BYTES_PER_LINE) { 488 if (i + j < len) 489 printk(" %#02x", buf[i + j++]); 490 } 491 492 i += JFFS3_BUFDUMP_BYTES_PER_LINE; 493 } 494 } 495 #endif /* JFFS2_PARANOIA_CHECKS || CONFIG_JFFS2_FS_DEBUG > 0 */ 496