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#include "yaffs_yaffs1.h" 14#include "yportenv.h" 15#include "yaffs_trace.h" 16#include "yaffs_bitmap.h" 17#include "yaffs_getblockinfo.h" 18#include "yaffs_nand.h" 19 20 21int yaffs1_scan(yaffs_dev_t *dev) 22{ 23 yaffs_ext_tags tags; 24 int blk; 25 int blockIterator; 26 int startIterator; 27 int endIterator; 28 int result; 29 30 int chunk; 31 int c; 32 int deleted; 33 yaffs_block_state_t state; 34 yaffs_obj_t *hard_list = NULL; 35 yaffs_block_info_t *bi; 36 __u32 seq_number; 37 yaffs_obj_header *oh; 38 yaffs_obj_t *in; 39 yaffs_obj_t *parent; 40 41 int alloc_failed = 0; 42 43 struct yaffs_shadow_fixer_s *shadowFixerList = NULL; 44 45 46 __u8 *chunkData; 47 48 49 50 T(YAFFS_TRACE_SCAN, 51 (TSTR("yaffs1_scan starts intstartblk %d intendblk %d..." TENDSTR), 52 dev->internal_start_block, dev->internal_end_block)); 53 54 chunkData = yaffs_get_temp_buffer(dev, __LINE__); 55 56 dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER; 57 58 /* Scan all the blocks to determine their state */ 59 bi = dev->block_info; 60 for (blk = dev->internal_start_block; blk <= dev->internal_end_block; blk++) { 61 yaffs_clear_chunk_bits(dev, blk); 62 bi->pages_in_use = 0; 63 bi->soft_del_pages = 0; 64 65 yaffs_query_init_block_state(dev, blk, &state, &seq_number); 66 67 bi->block_state = state; 68 bi->seq_number = seq_number; 69 70 if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK) 71 bi->block_state = state = YAFFS_BLOCK_STATE_DEAD; 72 73 T(YAFFS_TRACE_SCAN_DEBUG, 74 (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk, 75 state, seq_number)); 76 77 if (state == YAFFS_BLOCK_STATE_DEAD) { 78 T(YAFFS_TRACE_BAD_BLOCKS, 79 (TSTR("block %d is bad" TENDSTR), blk)); 80 } else if (state == YAFFS_BLOCK_STATE_EMPTY) { 81 T(YAFFS_TRACE_SCAN_DEBUG, 82 (TSTR("Block empty " TENDSTR))); 83 dev->n_erased_blocks++; 84 dev->n_free_chunks += dev->param.chunks_per_block; 85 } 86 bi++; 87 } 88 89 startIterator = dev->internal_start_block; 90 endIterator = dev->internal_end_block; 91 92 /* For each block.... */ 93 for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator; 94 blockIterator++) { 95 96 YYIELD(); 97 98 YYIELD(); 99 100 blk = blockIterator; 101 102 bi = yaffs_get_block_info(dev, blk); 103 state = bi->block_state; 104 105 deleted = 0; 106 107 /* For each chunk in each block that needs scanning....*/ 108 for (c = 0; !alloc_failed && c < dev->param.chunks_per_block && 109 state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) { 110 /* Read the tags and decide what to do */ 111 chunk = blk * dev->param.chunks_per_block + c; 112 113 result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL, 114 &tags); 115 116 /* Let's have a good look at this chunk... */ 117 118 if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED || tags.is_deleted) { 119 /* YAFFS1 only... 120 * A deleted chunk 121 */ 122 deleted++; 123 dev->n_free_chunks++; 124 /*T((" %d %d deleted\n",blk,c)); */ 125 } else if (!tags.chunk_used) { 126 /* An unassigned chunk in the block 127 * This means that either the block is empty or 128 * this is the one being allocated from 129 */ 130 131 if (c == 0) { 132 /* We're looking at the first chunk in the block so the block is unused */ 133 state = YAFFS_BLOCK_STATE_EMPTY; 134 dev->n_erased_blocks++; 135 } else { 136 /* this is the block being allocated from */ 137 T(YAFFS_TRACE_SCAN, 138 (TSTR 139 (" Allocating from %d %d" TENDSTR), 140 blk, c)); 141 state = YAFFS_BLOCK_STATE_ALLOCATING; 142 dev->alloc_block = blk; 143 dev->alloc_page = c; 144 dev->alloc_block_finder = blk; 145 /* Set block finder here to encourage the allocator to go forth from here. */ 146 147 } 148 149 dev->n_free_chunks += (dev->param.chunks_per_block - c); 150 } else if (tags.chunk_id > 0) { 151 /* chunk_id > 0 so it is a data chunk... */ 152 unsigned int endpos; 153 154 yaffs_set_chunk_bit(dev, blk, c); 155 bi->pages_in_use++; 156 157 in = yaffs_find_or_create_by_number(dev, 158 tags. 159 obj_id, 160 YAFFS_OBJECT_TYPE_FILE); 161 /* PutChunkIntoFile checks for a clash (two data chunks with 162 * the same chunk_id). 163 */ 164 165 if (!in) 166 alloc_failed = 1; 167 168 if (in) { 169 if (!yaffs_put_chunk_in_file(in, tags.chunk_id, chunk, 1)) 170 alloc_failed = 1; 171 } 172 173 endpos = 174 (tags.chunk_id - 1) * dev->data_bytes_per_chunk + 175 tags.n_bytes; 176 if (in && 177 in->variant_type == YAFFS_OBJECT_TYPE_FILE 178 && in->variant.file_variant.scanned_size < 179 endpos) { 180 in->variant.file_variant. 181 scanned_size = endpos; 182 if (!dev->param.use_header_file_size) { 183 in->variant.file_variant. 184 file_size = 185 in->variant.file_variant. 186 scanned_size; 187 } 188 189 } 190 /* T((" %d %d data %d %d\n",blk,c,tags.obj_id,tags.chunk_id)); */ 191 } else { 192 /* chunk_id == 0, so it is an ObjectHeader. 193 * Thus, we read in the object header and make the object 194 */ 195 yaffs_set_chunk_bit(dev, blk, c); 196 bi->pages_in_use++; 197 198 result = yaffs_rd_chunk_tags_nand(dev, chunk, 199 chunkData, 200 NULL); 201 202 oh = (yaffs_obj_header *) chunkData; 203 204 in = yaffs_find_by_number(dev, 205 tags.obj_id); 206 if (in && in->variant_type != oh->type) { 207 /* This should not happen, but somehow 208 * Wev'e ended up with an obj_id that has been reused but not yet 209 * deleted, and worse still it has changed type. Delete the old object. 210 */ 211 212 yaffs_del_obj(in); 213 214 in = 0; 215 } 216 217 in = yaffs_find_or_create_by_number(dev, 218 tags. 219 obj_id, 220 oh->type); 221 222 if (!in) 223 alloc_failed = 1; 224 225 if (in && oh->shadows_obj > 0) { 226 227 struct yaffs_shadow_fixer_s *fixer; 228 fixer = YMALLOC(sizeof(struct yaffs_shadow_fixer_s)); 229 if (fixer) { 230 fixer->next = shadowFixerList; 231 shadowFixerList = fixer; 232 fixer->obj_id = tags.obj_id; 233 fixer->shadowed_id = oh->shadows_obj; 234 T(YAFFS_TRACE_SCAN, 235 (TSTR 236 (" Shadow fixer: %d shadows %d" TENDSTR), 237 fixer->obj_id, fixer->shadowed_id)); 238 239 } 240 241 } 242 243 if (in && in->valid) { 244 /* We have already filled this one. We have a duplicate and need to resolve it. */ 245 246 unsigned existingSerial = in->serial; 247 unsigned newSerial = tags.serial_number; 248 249 if (((existingSerial + 1) & 3) == newSerial) { 250 /* Use new one - destroy the exisiting one */ 251 yaffs_chunk_del(dev, 252 in->hdr_chunk, 253 1, __LINE__); 254 in->valid = 0; 255 } else { 256 /* Use existing - destroy this one. */ 257 yaffs_chunk_del(dev, chunk, 1, 258 __LINE__); 259 } 260 } 261 262 if (in && !in->valid && 263 (tags.obj_id == YAFFS_OBJECTID_ROOT || 264 tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND)) { 265 /* We only load some info, don't fiddle with directory structure */ 266 in->valid = 1; 267 in->variant_type = oh->type; 268 269 in->yst_mode = oh->yst_mode; 270#ifdef CONFIG_YAFFS_WINCE 271 in->win_atime[0] = oh->win_atime[0]; 272 in->win_ctime[0] = oh->win_ctime[0]; 273 in->win_mtime[0] = oh->win_mtime[0]; 274 in->win_atime[1] = oh->win_atime[1]; 275 in->win_ctime[1] = oh->win_ctime[1]; 276 in->win_mtime[1] = oh->win_mtime[1]; 277#else 278 in->yst_uid = oh->yst_uid; 279 in->yst_gid = oh->yst_gid; 280 in->yst_atime = oh->yst_atime; 281 in->yst_mtime = oh->yst_mtime; 282 in->yst_ctime = oh->yst_ctime; 283 in->yst_rdev = oh->yst_rdev; 284#endif 285 in->hdr_chunk = chunk; 286 in->serial = tags.serial_number; 287 288 } else if (in && !in->valid) { 289 /* we need to load this info */ 290 291 in->valid = 1; 292 in->variant_type = oh->type; 293 294 in->yst_mode = oh->yst_mode; 295#ifdef CONFIG_YAFFS_WINCE 296 in->win_atime[0] = oh->win_atime[0]; 297 in->win_ctime[0] = oh->win_ctime[0]; 298 in->win_mtime[0] = oh->win_mtime[0]; 299 in->win_atime[1] = oh->win_atime[1]; 300 in->win_ctime[1] = oh->win_ctime[1]; 301 in->win_mtime[1] = oh->win_mtime[1]; 302#else 303 in->yst_uid = oh->yst_uid; 304 in->yst_gid = oh->yst_gid; 305 in->yst_atime = oh->yst_atime; 306 in->yst_mtime = oh->yst_mtime; 307 in->yst_ctime = oh->yst_ctime; 308 in->yst_rdev = oh->yst_rdev; 309#endif 310 in->hdr_chunk = chunk; 311 in->serial = tags.serial_number; 312 313 yaffs_set_obj_name_from_oh(in, oh); 314 in->dirty = 0; 315 316 /* directory stuff... 317 * hook up to parent 318 */ 319 320 parent = 321 yaffs_find_or_create_by_number 322 (dev, oh->parent_obj_id, 323 YAFFS_OBJECT_TYPE_DIRECTORY); 324 if (!parent) 325 alloc_failed = 1; 326 if (parent && parent->variant_type == 327 YAFFS_OBJECT_TYPE_UNKNOWN) { 328 /* Set up as a directory */ 329 parent->variant_type = 330 YAFFS_OBJECT_TYPE_DIRECTORY; 331 YINIT_LIST_HEAD(&parent->variant. 332 dir_variant. 333 children); 334 } else if (!parent || parent->variant_type != 335 YAFFS_OBJECT_TYPE_DIRECTORY) { 336 /* Hoosterman, another problem.... 337 * We're trying to use a non-directory as a directory 338 */ 339 340 T(YAFFS_TRACE_ERROR, 341 (TSTR 342 ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." 343 TENDSTR))); 344 parent = dev->lost_n_found; 345 } 346 347 yaffs_add_obj_to_dir(parent, in); 348 349 if (0 && (parent == dev->del_dir || 350 parent == dev->unlinked_dir)) { 351 in->deleted = 1; /* If it is unlinked at start up then it wants deleting */ 352 dev->n_deleted_files++; 353 } 354 /* Note re hardlinks. 355 * Since we might scan a hardlink before its equivalent object is scanned 356 * we put them all in a list. 357 * After scanning is complete, we should have all the objects, so we run through this 358 * list and fix up all the chains. 359 */ 360 361 switch (in->variant_type) { 362 case YAFFS_OBJECT_TYPE_UNKNOWN: 363 /* Todo got a problem */ 364 break; 365 case YAFFS_OBJECT_TYPE_FILE: 366 if (dev->param.use_header_file_size) 367 368 in->variant.file_variant. 369 file_size = 370 oh->file_size; 371 372 break; 373 case YAFFS_OBJECT_TYPE_HARDLINK: 374 in->variant.hardlink_variant. 375 equiv_id = 376 oh->equiv_id; 377 in->hard_links.next = 378 (struct ylist_head *) 379 hard_list; 380 hard_list = in; 381 break; 382 case YAFFS_OBJECT_TYPE_DIRECTORY: 383 /* Do nothing */ 384 break; 385 case YAFFS_OBJECT_TYPE_SPECIAL: 386 /* Do nothing */ 387 break; 388 case YAFFS_OBJECT_TYPE_SYMLINK: 389 in->variant.symlink_variant.alias = 390 yaffs_clone_str(oh->alias); 391 if (!in->variant.symlink_variant.alias) 392 alloc_failed = 1; 393 break; 394 } 395 396 } 397 } 398 } 399 400 if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { 401 /* If we got this far while scanning, then the block is fully allocated.*/ 402 state = YAFFS_BLOCK_STATE_FULL; 403 } 404 405 if (state == YAFFS_BLOCK_STATE_ALLOCATING) { 406 /* If the block was partially allocated then treat it as fully allocated.*/ 407 state = YAFFS_BLOCK_STATE_FULL; 408 dev->alloc_block = -1; 409 } 410 411 bi->block_state = state; 412 413 /* Now let's see if it was dirty */ 414 if (bi->pages_in_use == 0 && 415 !bi->has_shrink_hdr && 416 bi->block_state == YAFFS_BLOCK_STATE_FULL) { 417 yaffs_block_became_dirty(dev, blk); 418 } 419 420 } 421 422 423 /* Ok, we've done all the scanning. 424 * Fix up the hard link chains. 425 * We should now have scanned all the objects, now it's time to add these 426 * hardlinks. 427 */ 428 429 yaffs_link_fixup(dev, hard_list); 430 431 /* Fix up any shadowed objects */ 432 { 433 struct yaffs_shadow_fixer_s *fixer; 434 yaffs_obj_t *obj; 435 436 while (shadowFixerList) { 437 fixer = shadowFixerList; 438 shadowFixerList = fixer->next; 439 /* Complete the rename transaction by deleting the shadowed object 440 * then setting the object header to unshadowed. 441 */ 442 obj = yaffs_find_by_number(dev, fixer->shadowed_id); 443 if (obj) 444 yaffs_del_obj(obj); 445 446 obj = yaffs_find_by_number(dev, fixer->obj_id); 447 448 if (obj) 449 yaffs_update_oh(obj, NULL, 1, 0, 0, NULL); 450 451 YFREE(fixer); 452 } 453 } 454 455 yaffs_release_temp_buffer(dev, chunkData, __LINE__); 456 457 if (alloc_failed) 458 return YAFFS_FAIL; 459 460 T(YAFFS_TRACE_SCAN, (TSTR("yaffs1_scan ends" TENDSTR))); 461 462 463 return YAFFS_OK; 464} 465 466