1/* 2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. 3 * 4 * Copyright (C) 2002-2010 Aleph One Ltd. 5 * for Toby Churchill Ltd and Brightstar Engineering 6 * 7 * Created by Charles Manning <charles@aleph1.co.uk> 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 12 */ 13 14 15#include "yaffs_guts.h" 16#include "yaffs_trace.h" 17#include "yaffs_yaffs2.h" 18#include "yaffs_checkptrw.h" 19#include "yaffs_bitmap.h" 20#include "yaffs_qsort.h" 21#include "yaffs_nand.h" 22#include "yaffs_getblockinfo.h" 23#include "yaffs_verify.h" 24 25/* 26 * Checkpoints are really no benefit on very small partitions. 27 * 28 * To save space on small partitions don't bother with checkpoints unless 29 * the partition is at least this big. 30 */ 31#define YAFFS_CHECKPOINT_MIN_BLOCKS 60 32 33#define YAFFS_SMALL_HOLE_THRESHOLD 4 34 35 36/* 37 * Oldest Dirty Sequence Number handling. 38 */ 39 40/* yaffs_calc_oldest_dirty_seq() 41 * yaffs2_find_oldest_dirty_seq() 42 * Calculate the oldest dirty sequence number if we don't know it. 43 */ 44void yaffs_calc_oldest_dirty_seq(yaffs_dev_t *dev) 45{ 46 int i; 47 unsigned seq; 48 unsigned block_no = 0; 49 yaffs_block_info_t *b; 50 51 if(!dev->param.is_yaffs2) 52 return; 53 54 /* Find the oldest dirty sequence number. */ 55 seq = dev->seq_number + 1; 56 b = dev->block_info; 57 for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { 58 if (b->block_state == YAFFS_BLOCK_STATE_FULL && 59 (b->pages_in_use - b->soft_del_pages) < dev->param.chunks_per_block && 60 b->seq_number < seq) { 61 seq = b->seq_number; 62 block_no = i; 63 } 64 b++; 65 } 66 67 if(block_no){ 68 dev->oldest_dirty_seq = seq; 69 dev->oldest_dirty_block = block_no; 70 } 71 72} 73 74 75void yaffs2_find_oldest_dirty_seq(yaffs_dev_t *dev) 76{ 77 if(!dev->param.is_yaffs2) 78 return; 79 80 if(!dev->oldest_dirty_seq) 81 yaffs_calc_oldest_dirty_seq(dev); 82} 83 84/* 85 * yaffs_clear_oldest_dirty_seq() 86 * Called when a block is erased or marked bad. (ie. when its seq_number 87 * becomes invalid). If the value matches the oldest then we clear 88 * dev->oldest_dirty_seq to force its recomputation. 89 */ 90void yaffs2_clear_oldest_dirty_seq(yaffs_dev_t *dev, yaffs_block_info_t *bi) 91{ 92 93 if(!dev->param.is_yaffs2) 94 return; 95 96 if(!bi || bi->seq_number == dev->oldest_dirty_seq){ 97 dev->oldest_dirty_seq = 0; 98 dev->oldest_dirty_block = 0; 99 } 100} 101 102/* 103 * yaffs2_update_oldest_dirty_seq() 104 * Update the oldest dirty sequence number whenever we dirty a block. 105 * Only do this if the oldest_dirty_seq is actually being tracked. 106 */ 107void yaffs2_update_oldest_dirty_seq(yaffs_dev_t *dev, unsigned block_no, yaffs_block_info_t *bi) 108{ 109 if(!dev->param.is_yaffs2) 110 return; 111 112 if(dev->oldest_dirty_seq){ 113 if(dev->oldest_dirty_seq > bi->seq_number){ 114 dev->oldest_dirty_seq = bi->seq_number; 115 dev->oldest_dirty_block = block_no; 116 } 117 } 118} 119 120int yaffs_block_ok_for_gc(yaffs_dev_t *dev, 121 yaffs_block_info_t *bi) 122{ 123 124 if (!dev->param.is_yaffs2) 125 return 1; /* disqualification only applies to yaffs2. */ 126 127 if (!bi->has_shrink_hdr) 128 return 1; /* can gc */ 129 130 yaffs2_find_oldest_dirty_seq(dev); 131 132 /* Can't do gc of this block if there are any blocks older than this one that have 133 * discarded pages. 134 */ 135 return (bi->seq_number <= dev->oldest_dirty_seq); 136} 137 138/* 139 * yaffs2_find_refresh_block() 140 * periodically finds the oldest full block by sequence number for refreshing. 141 * Only for yaffs2. 142 */ 143__u32 yaffs2_find_refresh_block(yaffs_dev_t *dev) 144{ 145 __u32 b ; 146 147 __u32 oldest = 0; 148 __u32 oldestSequence = 0; 149 150 yaffs_block_info_t *bi; 151 152 if(!dev->param.is_yaffs2) 153 return oldest; 154 155 /* 156 * If refresh period < 10 then refreshing is disabled. 157 */ 158 if(dev->param.refresh_period < 10) 159 return oldest; 160 161 /* 162 * Fix broken values. 163 */ 164 if(dev->refresh_skip > dev->param.refresh_period) 165 dev->refresh_skip = dev->param.refresh_period; 166 167 if(dev->refresh_skip > 0) 168 return oldest; 169 170 /* 171 * Refresh skip is now zero. 172 * We'll do a refresh this time around.... 173 * Update the refresh skip and find the oldest block. 174 */ 175 dev->refresh_skip = dev->param.refresh_period; 176 dev->refresh_count++; 177 bi = dev->block_info; 178 for (b = dev->internal_start_block; b <=dev->internal_end_block; b++){ 179 180 if (bi->block_state == YAFFS_BLOCK_STATE_FULL){ 181 182 if(oldest < 1 || 183 bi->seq_number < oldestSequence){ 184 oldest = b; 185 oldestSequence = bi->seq_number; 186 } 187 } 188 bi++; 189 } 190 191 if (oldest > 0) { 192 T(YAFFS_TRACE_GC, 193 (TSTR("GC refresh count %d selected block %d with seq_number %d" TENDSTR), 194 dev->refresh_count, oldest, oldestSequence)); 195 } 196 197 return oldest; 198} 199 200int yaffs2_checkpt_required(yaffs_dev_t *dev) 201{ 202 int nblocks; 203 204 if(!dev->param.is_yaffs2) 205 return 0; 206 207 nblocks = dev->internal_end_block - dev->internal_start_block + 1 ; 208 209 return !dev->param.skip_checkpt_wr && 210 !dev->read_only && 211 (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS); 212} 213 214int yaffs_calc_checkpt_blocks_required(yaffs_dev_t *dev) 215{ 216 int retval; 217 218 if(!dev->param.is_yaffs2) 219 return 0; 220 221 if (!dev->checkpoint_blocks_required && 222 yaffs2_checkpt_required(dev)){ 223 /* Not a valid value so recalculate */ 224 int n_bytes = 0; 225 int nBlocks; 226 int devBlocks = (dev->param.end_block - dev->param.start_block + 1); 227 228 n_bytes += sizeof(yaffs_checkpt_validty_t); 229 n_bytes += sizeof(yaffs_checkpt_dev_t); 230 n_bytes += devBlocks * sizeof(yaffs_block_info_t); 231 n_bytes += devBlocks * dev->chunk_bit_stride; 232 n_bytes += (sizeof(yaffs_checkpt_obj_t) + sizeof(__u32)) * (dev->n_obj); 233 n_bytes += (dev->tnode_size + sizeof(__u32)) * (dev->n_tnodes); 234 n_bytes += sizeof(yaffs_checkpt_validty_t); 235 n_bytes += sizeof(__u32); /* checksum*/ 236 237 /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */ 238 239 nBlocks = (n_bytes/(dev->data_bytes_per_chunk * dev->param.chunks_per_block)) + 3; 240 241 dev->checkpoint_blocks_required = nBlocks; 242 } 243 244 retval = dev->checkpoint_blocks_required - dev->blocks_in_checkpt; 245 if(retval < 0) 246 retval = 0; 247 return retval; 248} 249 250/*--------------------- Checkpointing --------------------*/ 251 252 253static int yaffs2_wr_checkpt_validity_marker(yaffs_dev_t *dev, int head) 254{ 255 yaffs_checkpt_validty_t cp; 256 257 memset(&cp, 0, sizeof(cp)); 258 259 cp.struct_type = sizeof(cp); 260 cp.magic = YAFFS_MAGIC; 261 cp.version = YAFFS_CHECKPOINT_VERSION; 262 cp.head = (head) ? 1 : 0; 263 264 return (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)) ? 265 1 : 0; 266} 267 268static int yaffs2_rd_checkpt_validty_marker(yaffs_dev_t *dev, int head) 269{ 270 yaffs_checkpt_validty_t cp; 271 int ok; 272 273 ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp)); 274 275 if (ok) 276 ok = (cp.struct_type == sizeof(cp)) && 277 (cp.magic == YAFFS_MAGIC) && 278 (cp.version == YAFFS_CHECKPOINT_VERSION) && 279 (cp.head == ((head) ? 1 : 0)); 280 return ok ? 1 : 0; 281} 282 283static void yaffs2_dev_to_checkpt_dev(yaffs_checkpt_dev_t *cp, 284 yaffs_dev_t *dev) 285{ 286 cp->n_erased_blocks = dev->n_erased_blocks; 287 cp->alloc_block = dev->alloc_block; 288 cp->alloc_page = dev->alloc_page; 289 cp->n_free_chunks = dev->n_free_chunks; 290 291 cp->n_deleted_files = dev->n_deleted_files; 292 cp->n_unlinked_files = dev->n_unlinked_files; 293 cp->n_bg_deletions = dev->n_bg_deletions; 294 cp->seq_number = dev->seq_number; 295 296} 297 298static void yaffs_checkpt_dev_to_dev(yaffs_dev_t *dev, 299 yaffs_checkpt_dev_t *cp) 300{ 301 dev->n_erased_blocks = cp->n_erased_blocks; 302 dev->alloc_block = cp->alloc_block; 303 dev->alloc_page = cp->alloc_page; 304 dev->n_free_chunks = cp->n_free_chunks; 305 306 dev->n_deleted_files = cp->n_deleted_files; 307 dev->n_unlinked_files = cp->n_unlinked_files; 308 dev->n_bg_deletions = cp->n_bg_deletions; 309 dev->seq_number = cp->seq_number; 310} 311 312 313static int yaffs2_wr_checkpt_dev(yaffs_dev_t *dev) 314{ 315 yaffs_checkpt_dev_t cp; 316 __u32 n_bytes; 317 __u32 nBlocks = (dev->internal_end_block - dev->internal_start_block + 1); 318 319 int ok; 320 321 /* Write device runtime values*/ 322 yaffs2_dev_to_checkpt_dev(&cp, dev); 323 cp.struct_type = sizeof(cp); 324 325 ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)); 326 327 /* Write block info */ 328 if (ok) { 329 n_bytes = nBlocks * sizeof(yaffs_block_info_t); 330 ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) == n_bytes); 331 } 332 333 /* Write chunk bits */ 334 if (ok) { 335 n_bytes = nBlocks * dev->chunk_bit_stride; 336 ok = (yaffs2_checkpt_wr(dev, dev->chunk_bits, n_bytes) == n_bytes); 337 } 338 return ok ? 1 : 0; 339 340} 341 342static int yaffs2_rd_checkpt_dev(yaffs_dev_t *dev) 343{ 344 yaffs_checkpt_dev_t cp; 345 __u32 n_bytes; 346 __u32 nBlocks = (dev->internal_end_block - dev->internal_start_block + 1); 347 348 int ok; 349 350 ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp)); 351 if (!ok) 352 return 0; 353 354 if (cp.struct_type != sizeof(cp)) 355 return 0; 356 357 358 yaffs_checkpt_dev_to_dev(dev, &cp); 359 360 n_bytes = nBlocks * sizeof(yaffs_block_info_t); 361 362 ok = (yaffs2_checkpt_rd(dev, dev->block_info, n_bytes) == n_bytes); 363 364 if (!ok) 365 return 0; 366 n_bytes = nBlocks * dev->chunk_bit_stride; 367 368 ok = (yaffs2_checkpt_rd(dev, dev->chunk_bits, n_bytes) == n_bytes); 369 370 return ok ? 1 : 0; 371} 372 373static void yaffs2_obj_checkpt_obj(yaffs_checkpt_obj_t *cp, 374 yaffs_obj_t *obj) 375{ 376 377 cp->obj_id = obj->obj_id; 378 cp->parent_id = (obj->parent) ? obj->parent->obj_id : 0; 379 cp->hdr_chunk = obj->hdr_chunk; 380 cp->variant_type = obj->variant_type; 381 cp->deleted = obj->deleted; 382 cp->soft_del = obj->soft_del; 383 cp->unlinked = obj->unlinked; 384 cp->fake = obj->fake; 385 cp->rename_allowed = obj->rename_allowed; 386 cp->unlink_allowed = obj->unlink_allowed; 387 cp->serial = obj->serial; 388 cp->n_data_chunks = obj->n_data_chunks; 389 390 if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) 391 cp->size_or_equiv_obj = obj->variant.file_variant.file_size; 392 else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) 393 cp->size_or_equiv_obj = obj->variant.hardlink_variant.equiv_id; 394} 395 396static int taffs2_checkpt_obj_to_obj(yaffs_obj_t *obj, yaffs_checkpt_obj_t *cp) 397{ 398 399 yaffs_obj_t *parent; 400 401 if (obj->variant_type != cp->variant_type) { 402 T(YAFFS_TRACE_ERROR, (TSTR("Checkpoint read object %d type %d " 403 TCONT("chunk %d does not match existing object type %d") 404 TENDSTR), cp->obj_id, cp->variant_type, cp->hdr_chunk, 405 obj->variant_type)); 406 return 0; 407 } 408 409 obj->obj_id = cp->obj_id; 410 411 if (cp->parent_id) 412 parent = yaffs_find_or_create_by_number( 413 obj->my_dev, 414 cp->parent_id, 415 YAFFS_OBJECT_TYPE_DIRECTORY); 416 else 417 parent = NULL; 418 419 if (parent) { 420 if (parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { 421 T(YAFFS_TRACE_ALWAYS, (TSTR("Checkpoint read object %d parent %d type %d" 422 TCONT(" chunk %d Parent type, %d, not directory") 423 TENDSTR), 424 cp->obj_id, cp->parent_id, cp->variant_type, 425 cp->hdr_chunk, parent->variant_type)); 426 return 0; 427 } 428 yaffs_add_obj_to_dir(parent, obj); 429 } 430 431 obj->hdr_chunk = cp->hdr_chunk; 432 obj->variant_type = cp->variant_type; 433 obj->deleted = cp->deleted; 434 obj->soft_del = cp->soft_del; 435 obj->unlinked = cp->unlinked; 436 obj->fake = cp->fake; 437 obj->rename_allowed = cp->rename_allowed; 438 obj->unlink_allowed = cp->unlink_allowed; 439 obj->serial = cp->serial; 440 obj->n_data_chunks = cp->n_data_chunks; 441 442 if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) 443 obj->variant.file_variant.file_size = cp->size_or_equiv_obj; 444 else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) 445 obj->variant.hardlink_variant.equiv_id = cp->size_or_equiv_obj; 446 447 if (obj->hdr_chunk > 0) 448 obj->lazy_loaded = 1; 449 return 1; 450} 451 452 453 454static int yaffs2_checkpt_tnode_worker(yaffs_obj_t *in, yaffs_tnode_t *tn, 455 __u32 level, int chunk_offset) 456{ 457 int i; 458 yaffs_dev_t *dev = in->my_dev; 459 int ok = 1; 460 461 if (tn) { 462 if (level > 0) { 463 464 for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) { 465 if (tn->internal[i]) { 466 ok = yaffs2_checkpt_tnode_worker(in, 467 tn->internal[i], 468 level - 1, 469 (chunk_offset<<YAFFS_TNODES_INTERNAL_BITS) + i); 470 } 471 } 472 } else if (level == 0) { 473 __u32 baseOffset = chunk_offset << YAFFS_TNODES_LEVEL0_BITS; 474 ok = (yaffs2_checkpt_wr(dev, &baseOffset, sizeof(baseOffset)) == sizeof(baseOffset)); 475 if (ok) 476 ok = (yaffs2_checkpt_wr(dev, tn, dev->tnode_size) == dev->tnode_size); 477 } 478 } 479 480 return ok; 481 482} 483 484static int yaffs2_wr_checkpt_tnodes(yaffs_obj_t *obj) 485{ 486 __u32 endMarker = ~0; 487 int ok = 1; 488 489 if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) { 490 ok = yaffs2_checkpt_tnode_worker(obj, 491 obj->variant.file_variant.top, 492 obj->variant.file_variant.top_level, 493 0); 494 if (ok) 495 ok = (yaffs2_checkpt_wr(obj->my_dev, &endMarker, sizeof(endMarker)) == 496 sizeof(endMarker)); 497 } 498 499 return ok ? 1 : 0; 500} 501 502static int yaffs2_rd_checkpt_tnodes(yaffs_obj_t *obj) 503{ 504 __u32 baseChunk; 505 int ok = 1; 506 yaffs_dev_t *dev = obj->my_dev; 507 yaffs_file_s *fileStructPtr = &obj->variant.file_variant; 508 yaffs_tnode_t *tn; 509 int nread = 0; 510 511 ok = (yaffs2_checkpt_rd(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk)); 512 513 while (ok && (~baseChunk)) { 514 nread++; 515 /* Read level 0 tnode */ 516 517 518 tn = yaffs_get_tnode(dev); 519 if (tn){ 520 ok = (yaffs2_checkpt_rd(dev, tn, dev->tnode_size) == dev->tnode_size); 521 } else 522 ok = 0; 523 524 if (tn && ok) 525 ok = yaffs_add_find_tnode_0(dev, 526 fileStructPtr, 527 baseChunk, 528 tn) ? 1 : 0; 529 530 if (ok) 531 ok = (yaffs2_checkpt_rd(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk)); 532 533 } 534 535 T(YAFFS_TRACE_CHECKPOINT, ( 536 TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR), 537 nread, baseChunk, ok)); 538 539 return ok ? 1 : 0; 540} 541 542 543static int yaffs2_wr_checkpt_objs(yaffs_dev_t *dev) 544{ 545 yaffs_obj_t *obj; 546 yaffs_checkpt_obj_t cp; 547 int i; 548 int ok = 1; 549 struct ylist_head *lh; 550 551 552 /* Iterate through the objects in each hash entry, 553 * dumping them to the checkpointing stream. 554 */ 555 556 for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) { 557 ylist_for_each(lh, &dev->obj_bucket[i].list) { 558 if (lh) { 559 obj = ylist_entry(lh, yaffs_obj_t, hash_link); 560 if (!obj->defered_free) { 561 yaffs2_obj_checkpt_obj(&cp, obj); 562 cp.struct_type = sizeof(cp); 563 564 T(YAFFS_TRACE_CHECKPOINT, ( 565 TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %p" TENDSTR), 566 cp.obj_id, cp.parent_id, cp.variant_type, cp.hdr_chunk, obj)); 567 568 ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)); 569 570 if (ok && obj->variant_type == YAFFS_OBJECT_TYPE_FILE) 571 ok = yaffs2_wr_checkpt_tnodes(obj); 572 } 573 } 574 } 575 } 576 577 /* Dump end of list */ 578 memset(&cp, 0xFF, sizeof(yaffs_checkpt_obj_t)); 579 cp.struct_type = sizeof(cp); 580 581 if (ok) 582 ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)); 583 584 return ok ? 1 : 0; 585} 586 587static int yaffs2_rd_checkpt_objs(yaffs_dev_t *dev) 588{ 589 yaffs_obj_t *obj; 590 yaffs_checkpt_obj_t cp; 591 int ok = 1; 592 int done = 0; 593 yaffs_obj_t *hard_list = NULL; 594 595 while (ok && !done) { 596 ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp)); 597 if (cp.struct_type != sizeof(cp)) { 598 T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %d ok %d"TENDSTR), 599 cp.struct_type, (int)sizeof(cp), ok)); 600 ok = 0; 601 } 602 603 T(YAFFS_TRACE_CHECKPOINT, (TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR), 604 cp.obj_id, cp.parent_id, cp.variant_type, cp.hdr_chunk)); 605 606 if (ok && cp.obj_id == ~0) 607 done = 1; 608 else if (ok) { 609 obj = yaffs_find_or_create_by_number(dev, cp.obj_id, cp.variant_type); 610 if (obj) { 611 ok = taffs2_checkpt_obj_to_obj(obj, &cp); 612 if (!ok) 613 break; 614 if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) { 615 ok = yaffs2_rd_checkpt_tnodes(obj); 616 } else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) { 617 obj->hard_links.next = 618 (struct ylist_head *) hard_list; 619 hard_list = obj; 620 } 621 } else 622 ok = 0; 623 } 624 } 625 626 if (ok) 627 yaffs_link_fixup(dev, hard_list); 628 629 return ok ? 1 : 0; 630} 631 632static int yaffs2_wr_checkpt_sum(yaffs_dev_t *dev) 633{ 634 __u32 checkpt_sum; 635 int ok; 636 637 yaffs2_get_checkpt_sum(dev, &checkpt_sum); 638 639 ok = (yaffs2_checkpt_wr(dev, &checkpt_sum, sizeof(checkpt_sum)) == sizeof(checkpt_sum)); 640 641 if (!ok) 642 return 0; 643 644 return 1; 645} 646 647static int yaffs2_rd_checkpt_sum(yaffs_dev_t *dev) 648{ 649 __u32 checkpt_sum0; 650 __u32 checkpt_sum1; 651 int ok; 652 653 yaffs2_get_checkpt_sum(dev, &checkpt_sum0); 654 655 ok = (yaffs2_checkpt_rd(dev, &checkpt_sum1, sizeof(checkpt_sum1)) == sizeof(checkpt_sum1)); 656 657 if (!ok) 658 return 0; 659 660 if (checkpt_sum0 != checkpt_sum1) 661 return 0; 662 663 return 1; 664} 665 666 667static int yaffs2_wr_checkpt_data(yaffs_dev_t *dev) 668{ 669 int ok = 1; 670 671 if (!yaffs2_checkpt_required(dev)) { 672 T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR))); 673 ok = 0; 674 } 675 676 if (ok) 677 ok = yaffs2_checkpt_open(dev, 1); 678 679 if (ok) { 680 T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR))); 681 ok = yaffs2_wr_checkpt_validity_marker(dev, 1); 682 } 683 if (ok) { 684 T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint device" TENDSTR))); 685 ok = yaffs2_wr_checkpt_dev(dev); 686 } 687 if (ok) { 688 T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint objects" TENDSTR))); 689 ok = yaffs2_wr_checkpt_objs(dev); 690 } 691 if (ok) { 692 T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR))); 693 ok = yaffs2_wr_checkpt_validity_marker(dev, 0); 694 } 695 696 if (ok) 697 ok = yaffs2_wr_checkpt_sum(dev); 698 699 if (!yaffs_checkpt_close(dev)) 700 ok = 0; 701 702 if (ok) 703 dev->is_checkpointed = 1; 704 else 705 dev->is_checkpointed = 0; 706 707 return dev->is_checkpointed; 708} 709 710static int yaffs2_rd_checkpt_data(yaffs_dev_t *dev) 711{ 712 int ok = 1; 713 714 if(!dev->param.is_yaffs2) 715 ok = 0; 716 717 if (ok && dev->param.skip_checkpt_rd) { 718 T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint read" TENDSTR))); 719 ok = 0; 720 } 721 722 if (ok) 723 ok = yaffs2_checkpt_open(dev, 0); /* open for read */ 724 725 if (ok) { 726 T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR))); 727 ok = yaffs2_rd_checkpt_validty_marker(dev, 1); 728 } 729 if (ok) { 730 T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint device" TENDSTR))); 731 ok = yaffs2_rd_checkpt_dev(dev); 732 } 733 if (ok) { 734 T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint objects" TENDSTR))); 735 ok = yaffs2_rd_checkpt_objs(dev); 736 } 737 if (ok) { 738 T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR))); 739 ok = yaffs2_rd_checkpt_validty_marker(dev, 0); 740 } 741 742 if (ok) { 743 ok = yaffs2_rd_checkpt_sum(dev); 744 T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint checksum %d" TENDSTR), ok)); 745 } 746 747 if (!yaffs_checkpt_close(dev)) 748 ok = 0; 749 750 if (ok) 751 dev->is_checkpointed = 1; 752 else 753 dev->is_checkpointed = 0; 754 755 return ok ? 1 : 0; 756 757} 758 759void yaffs2_checkpt_invalidate(yaffs_dev_t *dev) 760{ 761 if (dev->is_checkpointed || 762 dev->blocks_in_checkpt > 0) { 763 dev->is_checkpointed = 0; 764 yaffs2_checkpt_invalidate_stream(dev); 765 } 766 if (dev->param.sb_dirty_fn) 767 dev->param.sb_dirty_fn(dev); 768} 769 770 771int yaffs_checkpoint_save(yaffs_dev_t *dev) 772{ 773 774 T(YAFFS_TRACE_CHECKPOINT, (TSTR("save entry: is_checkpointed %d"TENDSTR), dev->is_checkpointed)); 775 776 yaffs_verify_objects(dev); 777 yaffs_verify_blocks(dev); 778 yaffs_verify_free_chunks(dev); 779 780 if (!dev->is_checkpointed) { 781 yaffs2_checkpt_invalidate(dev); 782 yaffs2_wr_checkpt_data(dev); 783 } 784 785 T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: is_checkpointed %d"TENDSTR), dev->is_checkpointed)); 786 787 return dev->is_checkpointed; 788} 789 790int yaffs2_checkpt_restore(yaffs_dev_t *dev) 791{ 792 int retval; 793 T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore entry: is_checkpointed %d"TENDSTR), dev->is_checkpointed)); 794 795 retval = yaffs2_rd_checkpt_data(dev); 796 797 if (dev->is_checkpointed) { 798 yaffs_verify_objects(dev); 799 yaffs_verify_blocks(dev); 800 yaffs_verify_free_chunks(dev); 801 } 802 803 T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore exit: is_checkpointed %d"TENDSTR), dev->is_checkpointed)); 804 805 return retval; 806} 807 808int yaffs2_handle_hole(yaffs_obj_t *obj, loff_t new_size) 809{ 810 /* if newsSize > oldFileSize. 811 * We're going to be writing a hole. 812 * If the hole is small then write zeros otherwise write a start of hole marker. 813 */ 814 815 816 loff_t oldFileSize; 817 int increase; 818 int smallHole ; 819 int result = YAFFS_OK; 820 yaffs_dev_t *dev = NULL; 821 822 __u8 *localBuffer = NULL; 823 824 int smallIncreaseOk = 0; 825 826 if(!obj) 827 return YAFFS_FAIL; 828 829 if(obj->variant_type != YAFFS_OBJECT_TYPE_FILE) 830 return YAFFS_FAIL; 831 832 dev = obj->my_dev; 833 834 /* Bail out if not yaffs2 mode */ 835 if(!dev->param.is_yaffs2) 836 return YAFFS_OK; 837 838 oldFileSize = obj->variant.file_variant.file_size; 839 840 if (new_size <= oldFileSize) 841 return YAFFS_OK; 842 843 increase = new_size - oldFileSize; 844 845 if(increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->data_bytes_per_chunk && 846 yaffs_check_alloc_available(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1)) 847 smallHole = 1; 848 else 849 smallHole = 0; 850 851 if(smallHole) 852 localBuffer= yaffs_get_temp_buffer(dev, __LINE__); 853 854 if(localBuffer){ 855 /* fill hole with zero bytes */ 856 int pos = oldFileSize; 857 int thisWrite; 858 int written; 859 memset(localBuffer,0,dev->data_bytes_per_chunk); 860 smallIncreaseOk = 1; 861 862 while(increase > 0 && smallIncreaseOk){ 863 thisWrite = increase; 864 if(thisWrite > dev->data_bytes_per_chunk) 865 thisWrite = dev->data_bytes_per_chunk; 866 written = yaffs_do_file_wr(obj,localBuffer,pos,thisWrite,0); 867 if(written == thisWrite){ 868 pos += thisWrite; 869 increase -= thisWrite; 870 } else 871 smallIncreaseOk = 0; 872 } 873 874 yaffs_release_temp_buffer(dev,localBuffer,__LINE__); 875 876 /* If we were out of space then reverse any chunks we've added */ 877 if(!smallIncreaseOk) 878 yaffs_resize_file_down(obj, oldFileSize); 879 } 880 881 if (!smallIncreaseOk && 882 obj->parent && 883 obj->parent->obj_id != YAFFS_OBJECTID_UNLINKED && 884 obj->parent->obj_id != YAFFS_OBJECTID_DELETED){ 885 /* Write a hole start header with the old file size */ 886 yaffs_update_oh(obj, NULL, 0, 1, 0, NULL); 887 } 888 889 return result; 890 891} 892 893 894typedef struct { 895 int seq; 896 int block; 897} yaffs_BlockIndex; 898 899 900static int yaffs2_ybicmp(const void *a, const void *b) 901{ 902 register int aseq = ((yaffs_BlockIndex *)a)->seq; 903 register int bseq = ((yaffs_BlockIndex *)b)->seq; 904 register int ablock = ((yaffs_BlockIndex *)a)->block; 905 register int bblock = ((yaffs_BlockIndex *)b)->block; 906 if (aseq == bseq) 907 return ablock - bblock; 908 else 909 return aseq - bseq; 910} 911 912int yaffs2_scan_backwards(yaffs_dev_t *dev) 913{ 914 yaffs_ext_tags tags; 915 int blk; 916 int blockIterator; 917 int startIterator; 918 int endIterator; 919 int nBlocksToScan = 0; 920 921 int chunk; 922 int result; 923 int c; 924 int deleted; 925 yaffs_block_state_t state; 926 yaffs_obj_t *hard_list = NULL; 927 yaffs_block_info_t *bi; 928 __u32 seq_number; 929 yaffs_obj_header *oh; 930 yaffs_obj_t *in; 931 yaffs_obj_t *parent; 932 int nBlocks = dev->internal_end_block - dev->internal_start_block + 1; 933 int itsUnlinked; 934 __u8 *chunkData; 935 936 int file_size; 937 int is_shrink; 938 int foundChunksInBlock; 939 int equiv_id; 940 int alloc_failed = 0; 941 942 943 yaffs_BlockIndex *blockIndex = NULL; 944 int altBlockIndex = 0; 945 946 T(YAFFS_TRACE_SCAN, 947 (TSTR 948 ("yaffs2_scan_backwards starts intstartblk %d intendblk %d..." 949 TENDSTR), dev->internal_start_block, dev->internal_end_block)); 950 951 952 dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER; 953 954 blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex)); 955 956 if (!blockIndex) { 957 blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex)); 958 altBlockIndex = 1; 959 } 960 961 if (!blockIndex) { 962 T(YAFFS_TRACE_SCAN, 963 (TSTR("yaffs2_scan_backwards() could not allocate block index!" TENDSTR))); 964 return YAFFS_FAIL; 965 } 966 967 dev->blocks_in_checkpt = 0; 968 969 chunkData = yaffs_get_temp_buffer(dev, __LINE__); 970 971 /* Scan all the blocks to determine their state */ 972 bi = dev->block_info; 973 for (blk = dev->internal_start_block; blk <= dev->internal_end_block; blk++) { 974 yaffs_clear_chunk_bits(dev, blk); 975 bi->pages_in_use = 0; 976 bi->soft_del_pages = 0; 977 978 yaffs_query_init_block_state(dev, blk, &state, &seq_number); 979 980 bi->block_state = state; 981 bi->seq_number = seq_number; 982 983 if (bi->seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA) 984 bi->block_state = state = YAFFS_BLOCK_STATE_CHECKPOINT; 985 if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK) 986 bi->block_state = state = YAFFS_BLOCK_STATE_DEAD; 987 988 T(YAFFS_TRACE_SCAN_DEBUG, 989 (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk, 990 state, seq_number)); 991 992 993 if (state == YAFFS_BLOCK_STATE_CHECKPOINT) { 994 dev->blocks_in_checkpt++; 995 996 } else if (state == YAFFS_BLOCK_STATE_DEAD) { 997 T(YAFFS_TRACE_BAD_BLOCKS, 998 (TSTR("block %d is bad" TENDSTR), blk)); 999 } else if (state == YAFFS_BLOCK_STATE_EMPTY) { 1000 T(YAFFS_TRACE_SCAN_DEBUG, 1001 (TSTR("Block empty " TENDSTR))); 1002 dev->n_erased_blocks++; 1003 dev->n_free_chunks += dev->param.chunks_per_block; 1004 } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { 1005 1006 /* Determine the highest sequence number */ 1007 if (seq_number >= YAFFS_LOWEST_SEQUENCE_NUMBER && 1008 seq_number < YAFFS_HIGHEST_SEQUENCE_NUMBER) { 1009 1010 blockIndex[nBlocksToScan].seq = seq_number; 1011 blockIndex[nBlocksToScan].block = blk; 1012 1013 nBlocksToScan++; 1014 1015 if (seq_number >= dev->seq_number) 1016 dev->seq_number = seq_number; 1017 } else { 1018 /* TODO: Nasty sequence number! */ 1019 T(YAFFS_TRACE_SCAN, 1020 (TSTR 1021 ("Block scanning block %d has bad sequence number %d" 1022 TENDSTR), blk, seq_number)); 1023 1024 } 1025 } 1026 bi++; 1027 } 1028 1029 T(YAFFS_TRACE_SCAN, 1030 (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan)); 1031 1032 1033 1034 YYIELD(); 1035 1036 /* Sort the blocks by sequence number*/ 1037 yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), yaffs2_ybicmp); 1038 1039 YYIELD(); 1040 1041 T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR))); 1042 1043 /* Now scan the blocks looking at the data. */ 1044 startIterator = 0; 1045 endIterator = nBlocksToScan - 1; 1046 T(YAFFS_TRACE_SCAN_DEBUG, 1047 (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan)); 1048 1049 /* For each block.... backwards */ 1050 for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator; 1051 blockIterator--) { 1052 /* Cooperative multitasking! This loop can run for so 1053 long that watchdog timers expire. */ 1054 YYIELD(); 1055 1056 /* get the block to scan in the correct order */ 1057 blk = blockIndex[blockIterator].block; 1058 1059 bi = yaffs_get_block_info(dev, blk); 1060 1061 1062 state = bi->block_state; 1063 1064 deleted = 0; 1065 1066 /* For each chunk in each block that needs scanning.... */ 1067 foundChunksInBlock = 0; 1068 for (c = dev->param.chunks_per_block - 1; 1069 !alloc_failed && c >= 0 && 1070 (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING || 1071 state == YAFFS_BLOCK_STATE_ALLOCATING); c--) { 1072 /* Scan backwards... 1073 * Read the tags and decide what to do 1074 */ 1075 1076 chunk = blk * dev->param.chunks_per_block + c; 1077 1078 result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL, 1079 &tags); 1080 1081 /* Let's have a good look at this chunk... */ 1082 1083 if (!tags.chunk_used) { 1084 /* An unassigned chunk in the block. 1085 * If there are used chunks after this one, then 1086 * it is a chunk that was skipped due to failing the erased 1087 * check. Just skip it so that it can be deleted. 1088 * But, more typically, We get here when this is an unallocated 1089 * chunk and his means that either the block is empty or 1090 * this is the one being allocated from 1091 */ 1092 1093 if (foundChunksInBlock) { 1094 /* This is a chunk that was skipped due to failing the erased check */ 1095 } else if (c == 0) { 1096 /* We're looking at the first chunk in the block so the block is unused */ 1097 state = YAFFS_BLOCK_STATE_EMPTY; 1098 dev->n_erased_blocks++; 1099 } else { 1100 if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING || 1101 state == YAFFS_BLOCK_STATE_ALLOCATING) { 1102 if (dev->seq_number == bi->seq_number) { 1103 /* this is the block being allocated from */ 1104 1105 T(YAFFS_TRACE_SCAN, 1106 (TSTR 1107 (" Allocating from %d %d" 1108 TENDSTR), blk, c)); 1109 1110 state = YAFFS_BLOCK_STATE_ALLOCATING; 1111 dev->alloc_block = blk; 1112 dev->alloc_page = c; 1113 dev->alloc_block_finder = blk; 1114 } else { 1115 /* This is a partially written block that is not 1116 * the current allocation block. 1117 */ 1118 1119 T(YAFFS_TRACE_SCAN, 1120 (TSTR("Partially written block %d detected" TENDSTR), 1121 blk)); 1122 } 1123 } 1124 } 1125 1126 dev->n_free_chunks++; 1127 1128 } else if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED) { 1129 T(YAFFS_TRACE_SCAN, 1130 (TSTR(" Unfixed ECC in chunk(%d:%d), chunk ignored"TENDSTR), 1131 blk, c)); 1132 1133 dev->n_free_chunks++; 1134 1135 } else if (tags.obj_id > YAFFS_MAX_OBJECT_ID || 1136 tags.chunk_id > YAFFS_MAX_CHUNK_ID || 1137 (tags.chunk_id > 0 && tags.n_bytes > dev->data_bytes_per_chunk) || 1138 tags.seq_number != bi->seq_number ) { 1139 T(YAFFS_TRACE_SCAN, 1140 (TSTR("Chunk (%d:%d) with bad tags:obj = %d, chunk_id = %d, n_bytes = %d, ignored"TENDSTR), 1141 blk, c,tags.obj_id, tags.chunk_id, tags.n_bytes)); 1142 1143 dev->n_free_chunks++; 1144 1145 } else if (tags.chunk_id > 0) { 1146 /* chunk_id > 0 so it is a data chunk... */ 1147 unsigned int endpos; 1148 __u32 chunkBase = 1149 (tags.chunk_id - 1) * dev->data_bytes_per_chunk; 1150 1151 foundChunksInBlock = 1; 1152 1153 1154 yaffs_set_chunk_bit(dev, blk, c); 1155 bi->pages_in_use++; 1156 1157 in = yaffs_find_or_create_by_number(dev, 1158 tags. 1159 obj_id, 1160 YAFFS_OBJECT_TYPE_FILE); 1161 if (!in) { 1162 /* Out of memory */ 1163 alloc_failed = 1; 1164 } 1165 1166 if (in && 1167 in->variant_type == YAFFS_OBJECT_TYPE_FILE 1168 && chunkBase < in->variant.file_variant.shrink_size) { 1169 /* This has not been invalidated by a resize */ 1170 if (!yaffs_put_chunk_in_file(in, tags.chunk_id, chunk, -1)) { 1171 alloc_failed = 1; 1172 } 1173 1174 /* File size is calculated by looking at the data chunks if we have not 1175 * seen an object header yet. Stop this practice once we find an object header. 1176 */ 1177 endpos = chunkBase + tags.n_bytes; 1178 1179 if (!in->valid && /* have not got an object header yet */ 1180 in->variant.file_variant.scanned_size < endpos) { 1181 in->variant.file_variant.scanned_size = endpos; 1182 in->variant.file_variant.file_size = endpos; 1183 } 1184 1185 } else if (in) { 1186 /* This chunk has been invalidated by a resize, or a past file deletion 1187 * so delete the chunk*/ 1188 yaffs_chunk_del(dev, chunk, 1, __LINE__); 1189 1190 } 1191 } else { 1192 /* chunk_id == 0, so it is an ObjectHeader. 1193 * Thus, we read in the object header and make the object 1194 */ 1195 foundChunksInBlock = 1; 1196 1197 yaffs_set_chunk_bit(dev, blk, c); 1198 bi->pages_in_use++; 1199 1200 oh = NULL; 1201 in = NULL; 1202 1203 if (tags.extra_available) { 1204 in = yaffs_find_or_create_by_number(dev, 1205 tags.obj_id, 1206 tags.extra_obj_type); 1207 if (!in) 1208 alloc_failed = 1; 1209 } 1210 1211 if (!in || 1212 (!in->valid && dev->param.disable_lazy_load) || 1213 tags.extra_shadows || 1214 (!in->valid && 1215 (tags.obj_id == YAFFS_OBJECTID_ROOT || 1216 tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND))) { 1217 1218 /* If we don't have valid info then we need to read the chunk 1219 * TODO In future we can probably defer reading the chunk and 1220 * living with invalid data until needed. 1221 */ 1222 1223 result = yaffs_rd_chunk_tags_nand(dev, 1224 chunk, 1225 chunkData, 1226 NULL); 1227 1228 oh = (yaffs_obj_header *) chunkData; 1229 1230 if (dev->param.inband_tags) { 1231 /* Fix up the header if they got corrupted by inband tags */ 1232 oh->shadows_obj = oh->inband_shadowed_obj_id; 1233 oh->is_shrink = oh->inband_is_shrink; 1234 } 1235 1236 if (!in) { 1237 in = yaffs_find_or_create_by_number(dev, tags.obj_id, oh->type); 1238 if (!in) 1239 alloc_failed = 1; 1240 } 1241 1242 } 1243 1244 if (!in) { 1245 /* TODO Hoosterman we have a problem! */ 1246 T(YAFFS_TRACE_ERROR, 1247 (TSTR 1248 ("yaffs tragedy: Could not make object for object %d at chunk %d during scan" 1249 TENDSTR), tags.obj_id, chunk)); 1250 continue; 1251 } 1252 1253 if (in->valid) { 1254 /* We have already filled this one. 1255 * We have a duplicate that will be discarded, but 1256 * we first have to suck out resize info if it is a file. 1257 */ 1258 1259 if ((in->variant_type == YAFFS_OBJECT_TYPE_FILE) && 1260 ((oh && 1261 oh->type == YAFFS_OBJECT_TYPE_FILE) || 1262 (tags.extra_available && 1263 tags.extra_obj_type == YAFFS_OBJECT_TYPE_FILE))) { 1264 __u32 thisSize = 1265 (oh) ? oh->file_size : tags. 1266 extra_length; 1267 __u32 parent_obj_id = 1268 (oh) ? oh-> 1269 parent_obj_id : tags. 1270 extra_parent_id; 1271 1272 1273 is_shrink = 1274 (oh) ? oh->is_shrink : tags. 1275 extra_is_shrink; 1276 1277 /* If it is deleted (unlinked at start also means deleted) 1278 * we treat the file size as being zeroed at this point. 1279 */ 1280 if (parent_obj_id == 1281 YAFFS_OBJECTID_DELETED 1282 || parent_obj_id == 1283 YAFFS_OBJECTID_UNLINKED) { 1284 thisSize = 0; 1285 is_shrink = 1; 1286 } 1287 1288 if (is_shrink && in->variant.file_variant.shrink_size > thisSize) 1289 in->variant.file_variant.shrink_size = thisSize; 1290 1291 if (is_shrink) 1292 bi->has_shrink_hdr = 1; 1293 1294 } 1295 /* Use existing - destroy this one. */ 1296 yaffs_chunk_del(dev, chunk, 1, __LINE__); 1297 1298 } 1299 1300 if (!in->valid && in->variant_type != 1301 (oh ? oh->type : tags.extra_obj_type)) 1302 T(YAFFS_TRACE_ERROR, ( 1303 TSTR("yaffs tragedy: Bad object type, " 1304 TCONT("%d != %d, for object %d at chunk ") 1305 TCONT("%d during scan") 1306 TENDSTR), oh ? 1307 oh->type : tags.extra_obj_type, 1308 in->variant_type, tags.obj_id, 1309 chunk)); 1310 1311 if (!in->valid && 1312 (tags.obj_id == YAFFS_OBJECTID_ROOT || 1313 tags.obj_id == 1314 YAFFS_OBJECTID_LOSTNFOUND)) { 1315 /* We only load some info, don't fiddle with directory structure */ 1316 in->valid = 1; 1317 1318 if (oh) { 1319 1320 in->yst_mode = oh->yst_mode; 1321#ifdef CONFIG_YAFFS_WINCE 1322 in->win_atime[0] = oh->win_atime[0]; 1323 in->win_ctime[0] = oh->win_ctime[0]; 1324 in->win_mtime[0] = oh->win_mtime[0]; 1325 in->win_atime[1] = oh->win_atime[1]; 1326 in->win_ctime[1] = oh->win_ctime[1]; 1327 in->win_mtime[1] = oh->win_mtime[1]; 1328#else 1329 in->yst_uid = oh->yst_uid; 1330 in->yst_gid = oh->yst_gid; 1331 in->yst_atime = oh->yst_atime; 1332 in->yst_mtime = oh->yst_mtime; 1333 in->yst_ctime = oh->yst_ctime; 1334 in->yst_rdev = oh->yst_rdev; 1335 1336 in->lazy_loaded = 0; 1337 1338#endif 1339 } else 1340 in->lazy_loaded = 1; 1341 1342 in->hdr_chunk = chunk; 1343 1344 } else if (!in->valid) { 1345 /* we need to load this info */ 1346 1347 in->valid = 1; 1348 in->hdr_chunk = chunk; 1349 1350 if (oh) { 1351 in->variant_type = oh->type; 1352 1353 in->yst_mode = oh->yst_mode; 1354#ifdef CONFIG_YAFFS_WINCE 1355 in->win_atime[0] = oh->win_atime[0]; 1356 in->win_ctime[0] = oh->win_ctime[0]; 1357 in->win_mtime[0] = oh->win_mtime[0]; 1358 in->win_atime[1] = oh->win_atime[1]; 1359 in->win_ctime[1] = oh->win_ctime[1]; 1360 in->win_mtime[1] = oh->win_mtime[1]; 1361#else 1362 in->yst_uid = oh->yst_uid; 1363 in->yst_gid = oh->yst_gid; 1364 in->yst_atime = oh->yst_atime; 1365 in->yst_mtime = oh->yst_mtime; 1366 in->yst_ctime = oh->yst_ctime; 1367 in->yst_rdev = oh->yst_rdev; 1368#endif 1369 1370 if (oh->shadows_obj > 0) 1371 yaffs_handle_shadowed_obj(dev, 1372 oh-> 1373 shadows_obj, 1374 1); 1375 1376 1377 1378 yaffs_set_obj_name_from_oh(in, oh); 1379 parent = 1380 yaffs_find_or_create_by_number 1381 (dev, oh->parent_obj_id, 1382 YAFFS_OBJECT_TYPE_DIRECTORY); 1383 1384 file_size = oh->file_size; 1385 is_shrink = oh->is_shrink; 1386 equiv_id = oh->equiv_id; 1387 1388 } else { 1389 in->variant_type = tags.extra_obj_type; 1390 parent = 1391 yaffs_find_or_create_by_number 1392 (dev, tags.extra_parent_id, 1393 YAFFS_OBJECT_TYPE_DIRECTORY); 1394 file_size = tags.extra_length; 1395 is_shrink = tags.extra_is_shrink; 1396 equiv_id = tags.extra_equiv_id; 1397 in->lazy_loaded = 1; 1398 1399 } 1400 in->dirty = 0; 1401 1402 if (!parent) 1403 alloc_failed = 1; 1404 1405 /* directory stuff... 1406 * hook up to parent 1407 */ 1408 1409 if (parent && parent->variant_type == 1410 YAFFS_OBJECT_TYPE_UNKNOWN) { 1411 /* Set up as a directory */ 1412 parent->variant_type = 1413 YAFFS_OBJECT_TYPE_DIRECTORY; 1414 YINIT_LIST_HEAD(&parent->variant. 1415 dir_variant. 1416 children); 1417 } else if (!parent || parent->variant_type != 1418 YAFFS_OBJECT_TYPE_DIRECTORY) { 1419 /* Hoosterman, another problem.... 1420 * We're trying to use a non-directory as a directory 1421 */ 1422 1423 T(YAFFS_TRACE_ERROR, 1424 (TSTR 1425 ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." 1426 TENDSTR))); 1427 parent = dev->lost_n_found; 1428 } 1429 1430 yaffs_add_obj_to_dir(parent, in); 1431 1432 itsUnlinked = (parent == dev->del_dir) || 1433 (parent == dev->unlinked_dir); 1434 1435 if (is_shrink) { 1436 /* Mark the block as having a shrinkHeader */ 1437 bi->has_shrink_hdr = 1; 1438 } 1439 1440 /* Note re hardlinks. 1441 * Since we might scan a hardlink before its equivalent object is scanned 1442 * we put them all in a list. 1443 * After scanning is complete, we should have all the objects, so we run 1444 * through this list and fix up all the chains. 1445 */ 1446 1447 switch (in->variant_type) { 1448 case YAFFS_OBJECT_TYPE_UNKNOWN: 1449 /* Todo got a problem */ 1450 break; 1451 case YAFFS_OBJECT_TYPE_FILE: 1452 1453 if (in->variant.file_variant. 1454 scanned_size < file_size) { 1455 /* This covers the case where the file size is greater 1456 * than where the data is 1457 * This will happen if the file is resized to be larger 1458 * than its current data extents. 1459 */ 1460 in->variant.file_variant.file_size = file_size; 1461 in->variant.file_variant.scanned_size = file_size; 1462 } 1463 1464 if (in->variant.file_variant.shrink_size > file_size) 1465 in->variant.file_variant.shrink_size = file_size; 1466 1467 1468 break; 1469 case YAFFS_OBJECT_TYPE_HARDLINK: 1470 if (!itsUnlinked) { 1471 in->variant.hardlink_variant.equiv_id = 1472 equiv_id; 1473 in->hard_links.next = 1474 (struct ylist_head *) hard_list; 1475 hard_list = in; 1476 } 1477 break; 1478 case YAFFS_OBJECT_TYPE_DIRECTORY: 1479 /* Do nothing */ 1480 break; 1481 case YAFFS_OBJECT_TYPE_SPECIAL: 1482 /* Do nothing */ 1483 break; 1484 case YAFFS_OBJECT_TYPE_SYMLINK: 1485 if (oh) { 1486 in->variant.symlink_variant.alias = 1487 yaffs_clone_str(oh->alias); 1488 if (!in->variant.symlink_variant.alias) 1489 alloc_failed = 1; 1490 } 1491 break; 1492 } 1493 1494 } 1495 1496 } 1497 1498 } /* End of scanning for each chunk */ 1499 1500 if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { 1501 /* If we got this far while scanning, then the block is fully allocated. */ 1502 state = YAFFS_BLOCK_STATE_FULL; 1503 } 1504 1505 1506 bi->block_state = state; 1507 1508 /* Now let's see if it was dirty */ 1509 if (bi->pages_in_use == 0 && 1510 !bi->has_shrink_hdr && 1511 bi->block_state == YAFFS_BLOCK_STATE_FULL) { 1512 yaffs_block_became_dirty(dev, blk); 1513 } 1514 1515 } 1516 1517 yaffs_skip_rest_of_block(dev); 1518 1519 if (altBlockIndex) 1520 YFREE_ALT(blockIndex); 1521 else 1522 YFREE(blockIndex); 1523 1524 /* Ok, we've done all the scanning. 1525 * Fix up the hard link chains. 1526 * We should now have scanned all the objects, now it's time to add these 1527 * hardlinks. 1528 */ 1529 yaffs_link_fixup(dev, hard_list); 1530 1531 1532 yaffs_release_temp_buffer(dev, chunkData, __LINE__); 1533 1534 if (alloc_failed) 1535 return YAFFS_FAIL; 1536 1537 T(YAFFS_TRACE_SCAN, (TSTR("yaffs2_scan_backwards ends" TENDSTR))); 1538 1539 return YAFFS_OK; 1540} 1541