1 /* 2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. 3 * 4 * Copyright (C) 2002-2007 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 /* XXX U-BOOT XXX */ 15 #include <common.h> 16 17 const char *yaffs_guts_c_version = 18 "$Id: yaffs_guts.c,v 1.52 2007/10/16 00:45:05 charles Exp $"; 19 20 #include "yportenv.h" 21 #include "linux/stat.h" 22 23 #include "yaffsinterface.h" 24 #include "yaffsfs.h" 25 #include "yaffs_guts.h" 26 #include "yaffs_tagsvalidity.h" 27 28 #include "yaffs_tagscompat.h" 29 #ifndef CONFIG_YAFFS_USE_OWN_SORT 30 #include "yaffs_qsort.h" 31 #endif 32 #include "yaffs_nand.h" 33 34 #include "yaffs_checkptrw.h" 35 36 #include "yaffs_nand.h" 37 #include "yaffs_packedtags2.h" 38 39 #include "malloc.h" 40 41 #ifdef CONFIG_YAFFS_WINCE 42 void yfsd_LockYAFFS(BOOL fsLockOnly); 43 void yfsd_UnlockYAFFS(BOOL fsLockOnly); 44 #endif 45 46 #define YAFFS_PASSIVE_GC_CHUNKS 2 47 48 #include "yaffs_ecc.h" 49 50 51 /* Robustification (if it ever comes about...) */ 52 static void yaffs_RetireBlock(yaffs_Device * dev, int blockInNAND); 53 static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND, int erasedOk); 54 static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND, 55 const __u8 * data, 56 const yaffs_ExtendedTags * tags); 57 static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND, 58 const yaffs_ExtendedTags * tags); 59 60 /* Other local prototypes */ 61 static int yaffs_UnlinkObject( yaffs_Object *obj); 62 static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj); 63 64 static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList); 65 66 static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device * dev, 67 const __u8 * buffer, 68 yaffs_ExtendedTags * tags, 69 int useReserve); 70 static int yaffs_PutChunkIntoFile(yaffs_Object * in, int chunkInInode, 71 int chunkInNAND, int inScan); 72 73 static yaffs_Object *yaffs_CreateNewObject(yaffs_Device * dev, int number, 74 yaffs_ObjectType type); 75 static void yaffs_AddObjectToDirectory(yaffs_Object * directory, 76 yaffs_Object * obj); 77 static int yaffs_UpdateObjectHeader(yaffs_Object * in, const YCHAR * name, 78 int force, int isShrink, int shadows); 79 static void yaffs_RemoveObjectFromDirectory(yaffs_Object * obj); 80 static int yaffs_CheckStructures(void); 81 static int yaffs_DoGenericObjectDeletion(yaffs_Object * in); 82 83 static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blockNo); 84 85 static __u8 *yaffs_GetTempBuffer(yaffs_Device * dev, int lineNo); 86 static void yaffs_ReleaseTempBuffer(yaffs_Device * dev, __u8 * buffer, 87 int lineNo); 88 89 static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, 90 int chunkInNAND); 91 92 static int yaffs_UnlinkWorker(yaffs_Object * obj); 93 static void yaffs_DestroyObject(yaffs_Object * obj); 94 95 static int yaffs_TagsMatch(const yaffs_ExtendedTags * tags, int objectId, 96 int chunkInObject); 97 98 loff_t yaffs_GetFileSize(yaffs_Object * obj); 99 100 static int yaffs_AllocateChunk(yaffs_Device * dev, int useReserve, yaffs_BlockInfo **blockUsedPtr); 101 102 static void yaffs_VerifyFreeChunks(yaffs_Device * dev); 103 104 static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in); 105 106 #ifdef YAFFS_PARANOID 107 static int yaffs_CheckFileSanity(yaffs_Object * in); 108 #else 109 #define yaffs_CheckFileSanity(in) 110 #endif 111 112 static void yaffs_InvalidateWholeChunkCache(yaffs_Object * in); 113 static void yaffs_InvalidateChunkCache(yaffs_Object * object, int chunkId); 114 115 static void yaffs_InvalidateCheckpoint(yaffs_Device *dev); 116 117 static int yaffs_FindChunkInFile(yaffs_Object * in, int chunkInInode, 118 yaffs_ExtendedTags * tags); 119 120 static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos); 121 static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device * dev, 122 yaffs_FileStructure * fStruct, 123 __u32 chunkId); 124 125 126 /* Function to calculate chunk and offset */ 127 128 static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, __u32 *chunk, __u32 *offset) 129 { 130 if(dev->chunkShift){ 131 /* Easy-peasy power of 2 case */ 132 *chunk = (__u32)(addr >> dev->chunkShift); 133 *offset = (__u32)(addr & dev->chunkMask); 134 } 135 else if(dev->crumbsPerChunk) 136 { 137 /* Case where we're using "crumbs" */ 138 *offset = (__u32)(addr & dev->crumbMask); 139 addr >>= dev->crumbShift; 140 *chunk = ((__u32)addr)/dev->crumbsPerChunk; 141 *offset += ((addr - (*chunk * dev->crumbsPerChunk)) << dev->crumbShift); 142 } 143 else 144 YBUG(); 145 } 146 147 /* Function to return the number of shifts for a power of 2 greater than or equal 148 * to the given number 149 * Note we don't try to cater for all possible numbers and this does not have to 150 * be hellishly efficient. 151 */ 152 153 static __u32 ShiftsGE(__u32 x) 154 { 155 int extraBits; 156 int nShifts; 157 158 nShifts = extraBits = 0; 159 160 while(x>1){ 161 if(x & 1) extraBits++; 162 x>>=1; 163 nShifts++; 164 } 165 166 if(extraBits) 167 nShifts++; 168 169 return nShifts; 170 } 171 172 /* Function to return the number of shifts to get a 1 in bit 0 173 */ 174 175 static __u32 ShiftDiv(__u32 x) 176 { 177 int nShifts; 178 179 nShifts = 0; 180 181 if(!x) return 0; 182 183 while( !(x&1)){ 184 x>>=1; 185 nShifts++; 186 } 187 188 return nShifts; 189 } 190 191 192 193 /* 194 * Temporary buffer manipulations. 195 */ 196 197 static int yaffs_InitialiseTempBuffers(yaffs_Device *dev) 198 { 199 int i; 200 __u8 *buf = (__u8 *)1; 201 202 memset(dev->tempBuffer,0,sizeof(dev->tempBuffer)); 203 204 for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) { 205 dev->tempBuffer[i].line = 0; /* not in use */ 206 dev->tempBuffer[i].buffer = buf = 207 YMALLOC_DMA(dev->nDataBytesPerChunk); 208 } 209 210 return buf ? YAFFS_OK : YAFFS_FAIL; 211 212 } 213 214 static __u8 *yaffs_GetTempBuffer(yaffs_Device * dev, int lineNo) 215 { 216 int i, j; 217 for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { 218 if (dev->tempBuffer[i].line == 0) { 219 dev->tempBuffer[i].line = lineNo; 220 if ((i + 1) > dev->maxTemp) { 221 dev->maxTemp = i + 1; 222 for (j = 0; j <= i; j++) 223 dev->tempBuffer[j].maxLine = 224 dev->tempBuffer[j].line; 225 } 226 227 return dev->tempBuffer[i].buffer; 228 } 229 } 230 231 T(YAFFS_TRACE_BUFFERS, 232 (TSTR("Out of temp buffers at line %d, other held by lines:"), 233 lineNo)); 234 for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { 235 T(YAFFS_TRACE_BUFFERS, (TSTR(" %d "), dev->tempBuffer[i].line)); 236 } 237 T(YAFFS_TRACE_BUFFERS, (TSTR(" " TENDSTR))); 238 239 /* 240 * If we got here then we have to allocate an unmanaged one 241 * This is not good. 242 */ 243 244 dev->unmanagedTempAllocations++; 245 return YMALLOC(dev->nDataBytesPerChunk); 246 247 } 248 249 static void yaffs_ReleaseTempBuffer(yaffs_Device * dev, __u8 * buffer, 250 int lineNo) 251 { 252 int i; 253 for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { 254 if (dev->tempBuffer[i].buffer == buffer) { 255 dev->tempBuffer[i].line = 0; 256 return; 257 } 258 } 259 260 if (buffer) { 261 /* assume it is an unmanaged one. */ 262 T(YAFFS_TRACE_BUFFERS, 263 (TSTR("Releasing unmanaged temp buffer in line %d" TENDSTR), 264 lineNo)); 265 YFREE(buffer); 266 dev->unmanagedTempDeallocations++; 267 } 268 269 } 270 271 /* 272 * Determine if we have a managed buffer. 273 */ 274 int yaffs_IsManagedTempBuffer(yaffs_Device * dev, const __u8 * buffer) 275 { 276 int i; 277 for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { 278 if (dev->tempBuffer[i].buffer == buffer) 279 return 1; 280 281 } 282 283 for (i = 0; i < dev->nShortOpCaches; i++) { 284 if( dev->srCache[i].data == buffer ) 285 return 1; 286 287 } 288 289 if (buffer == dev->checkpointBuffer) 290 return 1; 291 292 T(YAFFS_TRACE_ALWAYS, 293 (TSTR("yaffs: unmaged buffer detected.\n" TENDSTR))); 294 return 0; 295 } 296 297 298 299 /* 300 * Chunk bitmap manipulations 301 */ 302 303 static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device * dev, int blk) 304 { 305 if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) { 306 T(YAFFS_TRACE_ERROR, 307 (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR), 308 blk)); 309 YBUG(); 310 } 311 return dev->chunkBits + 312 (dev->chunkBitmapStride * (blk - dev->internalStartBlock)); 313 } 314 315 static Y_INLINE void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk) 316 { 317 if(blk < dev->internalStartBlock || blk > dev->internalEndBlock || 318 chunk < 0 || chunk >= dev->nChunksPerBlock) { 319 T(YAFFS_TRACE_ERROR, 320 (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),blk,chunk)); 321 YBUG(); 322 } 323 } 324 325 static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device * dev, int blk) 326 { 327 __u8 *blkBits = yaffs_BlockBits(dev, blk); 328 329 memset(blkBits, 0, dev->chunkBitmapStride); 330 } 331 332 static Y_INLINE void yaffs_ClearChunkBit(yaffs_Device * dev, int blk, int chunk) 333 { 334 __u8 *blkBits = yaffs_BlockBits(dev, blk); 335 336 yaffs_VerifyChunkBitId(dev,blk,chunk); 337 338 blkBits[chunk / 8] &= ~(1 << (chunk & 7)); 339 } 340 341 static Y_INLINE void yaffs_SetChunkBit(yaffs_Device * dev, int blk, int chunk) 342 { 343 __u8 *blkBits = yaffs_BlockBits(dev, blk); 344 345 yaffs_VerifyChunkBitId(dev,blk,chunk); 346 347 blkBits[chunk / 8] |= (1 << (chunk & 7)); 348 } 349 350 static Y_INLINE int yaffs_CheckChunkBit(yaffs_Device * dev, int blk, int chunk) 351 { 352 __u8 *blkBits = yaffs_BlockBits(dev, blk); 353 yaffs_VerifyChunkBitId(dev,blk,chunk); 354 355 return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0; 356 } 357 358 static Y_INLINE int yaffs_StillSomeChunkBits(yaffs_Device * dev, int blk) 359 { 360 __u8 *blkBits = yaffs_BlockBits(dev, blk); 361 int i; 362 for (i = 0; i < dev->chunkBitmapStride; i++) { 363 if (*blkBits) 364 return 1; 365 blkBits++; 366 } 367 return 0; 368 } 369 370 static int yaffs_CountChunkBits(yaffs_Device * dev, int blk) 371 { 372 __u8 *blkBits = yaffs_BlockBits(dev, blk); 373 int i; 374 int n = 0; 375 for (i = 0; i < dev->chunkBitmapStride; i++) { 376 __u8 x = *blkBits; 377 while(x){ 378 if(x & 1) 379 n++; 380 x >>=1; 381 } 382 383 blkBits++; 384 } 385 return n; 386 } 387 388 /* 389 * Verification code 390 */ 391 392 static Y_INLINE int yaffs_SkipVerification(yaffs_Device *dev) 393 { 394 return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL)); 395 } 396 397 static Y_INLINE int yaffs_SkipFullVerification(yaffs_Device *dev) 398 { 399 return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL)); 400 } 401 402 static Y_INLINE int yaffs_SkipNANDVerification(yaffs_Device *dev) 403 { 404 return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND)); 405 } 406 407 static const char * blockStateName[] = { 408 "Unknown", 409 "Needs scanning", 410 "Scanning", 411 "Empty", 412 "Allocating", 413 "Full", 414 "Dirty", 415 "Checkpoint", 416 "Collecting", 417 "Dead" 418 }; 419 420 static void yaffs_VerifyBlock(yaffs_Device *dev,yaffs_BlockInfo *bi,int n) 421 { 422 int actuallyUsed; 423 int inUse; 424 425 if(yaffs_SkipVerification(dev)) 426 return; 427 428 /* Report illegal runtime states */ 429 if(bi->blockState <0 || bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES) 430 T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has undefined state %d"TENDSTR),n,bi->blockState)); 431 432 switch(bi->blockState){ 433 case YAFFS_BLOCK_STATE_UNKNOWN: 434 case YAFFS_BLOCK_STATE_SCANNING: 435 case YAFFS_BLOCK_STATE_NEEDS_SCANNING: 436 T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has bad run-state %s"TENDSTR), 437 n,blockStateName[bi->blockState])); 438 } 439 440 /* Check pages in use and soft deletions are legal */ 441 442 actuallyUsed = bi->pagesInUse - bi->softDeletions; 443 444 if(bi->pagesInUse < 0 || bi->pagesInUse > dev->nChunksPerBlock || 445 bi->softDeletions < 0 || bi->softDeletions > dev->nChunksPerBlock || 446 actuallyUsed < 0 || actuallyUsed > dev->nChunksPerBlock) 447 T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR), 448 n,bi->pagesInUse,bi->softDeletions)); 449 450 451 /* Check chunk bitmap legal */ 452 inUse = yaffs_CountChunkBits(dev,n); 453 if(inUse != bi->pagesInUse) 454 T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR), 455 n,bi->pagesInUse,inUse)); 456 457 /* Check that the sequence number is valid. 458 * Ten million is legal, but is very unlikely 459 */ 460 if(dev->isYaffs2 && 461 (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || bi->blockState == YAFFS_BLOCK_STATE_FULL) && 462 (bi->sequenceNumber < YAFFS_LOWEST_SEQUENCE_NUMBER || bi->sequenceNumber > 10000000 )) 463 T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has suspect sequence number of %d"TENDSTR), 464 n,bi->sequenceNumber)); 465 466 } 467 468 static void yaffs_VerifyCollectedBlock(yaffs_Device *dev,yaffs_BlockInfo *bi,int n) 469 { 470 yaffs_VerifyBlock(dev,bi,n); 471 472 /* After collection the block should be in the erased state */ 473 /* TODO: This will need to change if we do partial gc */ 474 475 if(bi->blockState != YAFFS_BLOCK_STATE_EMPTY){ 476 T(YAFFS_TRACE_ERROR,(TSTR("Block %d is in state %d after gc, should be erased"TENDSTR), 477 n,bi->blockState)); 478 } 479 } 480 481 static void yaffs_VerifyBlocks(yaffs_Device *dev) 482 { 483 int i; 484 int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES]; 485 int nIllegalBlockStates = 0; 486 487 488 if(yaffs_SkipVerification(dev)) 489 return; 490 491 memset(nBlocksPerState,0,sizeof(nBlocksPerState)); 492 493 494 for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++){ 495 yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i); 496 yaffs_VerifyBlock(dev,bi,i); 497 498 if(bi->blockState >=0 && bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES) 499 nBlocksPerState[bi->blockState]++; 500 else 501 nIllegalBlockStates++; 502 503 } 504 505 T(YAFFS_TRACE_VERIFY,(TSTR(""TENDSTR))); 506 T(YAFFS_TRACE_VERIFY,(TSTR("Block summary"TENDSTR))); 507 508 T(YAFFS_TRACE_VERIFY,(TSTR("%d blocks have illegal states"TENDSTR),nIllegalBlockStates)); 509 if(nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1) 510 T(YAFFS_TRACE_VERIFY,(TSTR("Too many allocating blocks"TENDSTR))); 511 512 for(i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++) 513 T(YAFFS_TRACE_VERIFY, 514 (TSTR("%s %d blocks"TENDSTR), 515 blockStateName[i],nBlocksPerState[i])); 516 517 if(dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]) 518 T(YAFFS_TRACE_VERIFY, 519 (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR), 520 dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])); 521 522 if(dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]) 523 T(YAFFS_TRACE_VERIFY, 524 (TSTR("Erased block count wrong dev %d count %d"TENDSTR), 525 dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])); 526 527 if(nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1) 528 T(YAFFS_TRACE_VERIFY, 529 (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR), 530 nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING])); 531 532 T(YAFFS_TRACE_VERIFY,(TSTR(""TENDSTR))); 533 534 } 535 536 /* 537 * Verify the object header. oh must be valid, but obj and tags may be NULL in which 538 * case those tests will not be performed. 539 */ 540 static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck) 541 { 542 if(yaffs_SkipVerification(obj->myDev)) 543 return; 544 545 if(!(tags && obj && oh)){ 546 T(YAFFS_TRACE_VERIFY, 547 (TSTR("Verifying object header tags %x obj %x oh %x"TENDSTR), 548 (__u32)tags,(__u32)obj,(__u32)oh)); 549 return; 550 } 551 552 if(oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN || 553 oh->type > YAFFS_OBJECT_TYPE_MAX) 554 T(YAFFS_TRACE_VERIFY, 555 (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR), 556 tags->objectId, oh->type)); 557 558 if(tags->objectId != obj->objectId) 559 T(YAFFS_TRACE_VERIFY, 560 (TSTR("Obj %d header mismatch objectId %d"TENDSTR), 561 tags->objectId, obj->objectId)); 562 563 564 /* 565 * Check that the object's parent ids match if parentCheck requested. 566 * 567 * Tests do not apply to the root object. 568 */ 569 570 if(parentCheck && tags->objectId > 1 && !obj->parent) 571 T(YAFFS_TRACE_VERIFY, 572 (TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR), 573 tags->objectId, oh->parentObjectId)); 574 575 576 if(parentCheck && obj->parent && 577 oh->parentObjectId != obj->parent->objectId && 578 (oh->parentObjectId != YAFFS_OBJECTID_UNLINKED || 579 obj->parent->objectId != YAFFS_OBJECTID_DELETED)) 580 T(YAFFS_TRACE_VERIFY, 581 (TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR), 582 tags->objectId, oh->parentObjectId, obj->parent->objectId)); 583 584 585 if(tags->objectId > 1 && oh->name[0] == 0) /* Null name */ 586 T(YAFFS_TRACE_VERIFY, 587 (TSTR("Obj %d header name is NULL"TENDSTR), 588 obj->objectId)); 589 590 if(tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */ 591 T(YAFFS_TRACE_VERIFY, 592 (TSTR("Obj %d header name is 0xFF"TENDSTR), 593 obj->objectId)); 594 } 595 596 static void yaffs_VerifyFile(yaffs_Object *obj) 597 { 598 int requiredTallness; 599 int actualTallness; 600 __u32 lastChunk; 601 __u32 x; 602 __u32 i; 603 yaffs_Device *dev; 604 yaffs_ExtendedTags tags; 605 yaffs_Tnode *tn; 606 __u32 objectId; 607 608 if(obj && yaffs_SkipVerification(obj->myDev)) 609 return; 610 611 dev = obj->myDev; 612 objectId = obj->objectId; 613 614 /* Check file size is consistent with tnode depth */ 615 lastChunk = obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1; 616 x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS; 617 requiredTallness = 0; 618 while (x> 0) { 619 x >>= YAFFS_TNODES_INTERNAL_BITS; 620 requiredTallness++; 621 } 622 623 actualTallness = obj->variant.fileVariant.topLevel; 624 625 if(requiredTallness > actualTallness ) 626 T(YAFFS_TRACE_VERIFY, 627 (TSTR("Obj %d had tnode tallness %d, needs to be %d"TENDSTR), 628 obj->objectId,actualTallness, requiredTallness)); 629 630 631 /* Check that the chunks in the tnode tree are all correct. 632 * We do this by scanning through the tnode tree and 633 * checking the tags for every chunk match. 634 */ 635 636 if(yaffs_SkipNANDVerification(dev)) 637 return; 638 639 for(i = 1; i <= lastChunk; i++){ 640 tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant,i); 641 642 if (tn) { 643 __u32 theChunk = yaffs_GetChunkGroupBase(dev,tn,i); 644 if(theChunk > 0){ 645 /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */ 646 yaffs_ReadChunkWithTagsFromNAND(dev,theChunk,NULL, &tags); 647 if(tags.objectId != objectId || tags.chunkId != i){ 648 T(~0,(TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR), 649 objectId, i, theChunk, 650 tags.objectId, tags.chunkId)); 651 } 652 } 653 } 654 655 } 656 657 } 658 659 static void yaffs_VerifyDirectory(yaffs_Object *obj) 660 { 661 if(obj && yaffs_SkipVerification(obj->myDev)) 662 return; 663 664 } 665 666 static void yaffs_VerifyHardLink(yaffs_Object *obj) 667 { 668 if(obj && yaffs_SkipVerification(obj->myDev)) 669 return; 670 671 /* Verify sane equivalent object */ 672 } 673 674 static void yaffs_VerifySymlink(yaffs_Object *obj) 675 { 676 if(obj && yaffs_SkipVerification(obj->myDev)) 677 return; 678 679 /* Verify symlink string */ 680 } 681 682 static void yaffs_VerifySpecial(yaffs_Object *obj) 683 { 684 if(obj && yaffs_SkipVerification(obj->myDev)) 685 return; 686 } 687 688 static void yaffs_VerifyObject(yaffs_Object *obj) 689 { 690 yaffs_Device *dev; 691 692 __u32 chunkMin; 693 __u32 chunkMax; 694 695 __u32 chunkIdOk; 696 __u32 chunkIsLive; 697 698 if(!obj) 699 return; 700 701 dev = obj->myDev; 702 703 if(yaffs_SkipVerification(dev)) 704 return; 705 706 /* Check sane object header chunk */ 707 708 chunkMin = dev->internalStartBlock * dev->nChunksPerBlock; 709 chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1; 710 711 chunkIdOk = (obj->chunkId >= chunkMin && obj->chunkId <= chunkMax); 712 chunkIsLive = chunkIdOk && 713 yaffs_CheckChunkBit(dev, 714 obj->chunkId / dev->nChunksPerBlock, 715 obj->chunkId % dev->nChunksPerBlock); 716 if(!obj->fake && 717 (!chunkIdOk || !chunkIsLive)) { 718 T(YAFFS_TRACE_VERIFY, 719 (TSTR("Obj %d has chunkId %d %s %s"TENDSTR), 720 obj->objectId,obj->chunkId, 721 chunkIdOk ? "" : ",out of range", 722 chunkIsLive || !chunkIdOk ? "" : ",marked as deleted")); 723 } 724 725 if(chunkIdOk && chunkIsLive &&!yaffs_SkipNANDVerification(dev)) { 726 yaffs_ExtendedTags tags; 727 yaffs_ObjectHeader *oh; 728 __u8 *buffer = yaffs_GetTempBuffer(dev,__LINE__); 729 730 oh = (yaffs_ObjectHeader *)buffer; 731 732 yaffs_ReadChunkWithTagsFromNAND(dev, obj->chunkId,buffer, &tags); 733 734 yaffs_VerifyObjectHeader(obj,oh,&tags,1); 735 736 yaffs_ReleaseTempBuffer(dev,buffer,__LINE__); 737 } 738 739 /* Verify it has a parent */ 740 if(obj && !obj->fake && 741 (!obj->parent || obj->parent->myDev != dev)){ 742 T(YAFFS_TRACE_VERIFY, 743 (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR), 744 obj->objectId,obj->parent)); 745 } 746 747 /* Verify parent is a directory */ 748 if(obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY){ 749 T(YAFFS_TRACE_VERIFY, 750 (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR), 751 obj->objectId,obj->parent->variantType)); 752 } 753 754 switch(obj->variantType){ 755 case YAFFS_OBJECT_TYPE_FILE: 756 yaffs_VerifyFile(obj); 757 break; 758 case YAFFS_OBJECT_TYPE_SYMLINK: 759 yaffs_VerifySymlink(obj); 760 break; 761 case YAFFS_OBJECT_TYPE_DIRECTORY: 762 yaffs_VerifyDirectory(obj); 763 break; 764 case YAFFS_OBJECT_TYPE_HARDLINK: 765 yaffs_VerifyHardLink(obj); 766 break; 767 case YAFFS_OBJECT_TYPE_SPECIAL: 768 yaffs_VerifySpecial(obj); 769 break; 770 case YAFFS_OBJECT_TYPE_UNKNOWN: 771 default: 772 T(YAFFS_TRACE_VERIFY, 773 (TSTR("Obj %d has illegaltype %d"TENDSTR), 774 obj->objectId,obj->variantType)); 775 break; 776 } 777 778 779 } 780 781 static void yaffs_VerifyObjects(yaffs_Device *dev) 782 { 783 yaffs_Object *obj; 784 int i; 785 struct list_head *lh; 786 787 if(yaffs_SkipVerification(dev)) 788 return; 789 790 /* Iterate through the objects in each hash entry */ 791 792 for(i = 0; i < YAFFS_NOBJECT_BUCKETS; i++){ 793 list_for_each(lh, &dev->objectBucket[i].list) { 794 if (lh) { 795 obj = list_entry(lh, yaffs_Object, hashLink); 796 yaffs_VerifyObject(obj); 797 } 798 } 799 } 800 801 } 802 803 804 /* 805 * Simple hash function. Needs to have a reasonable spread 806 */ 807 808 static Y_INLINE int yaffs_HashFunction(int n) 809 { 810 /* XXX U-BOOT XXX */ 811 /*n = abs(n); */ 812 if (n < 0) 813 n = -n; 814 return (n % YAFFS_NOBJECT_BUCKETS); 815 } 816 817 /* 818 * Access functions to useful fake objects 819 */ 820 821 yaffs_Object *yaffs_Root(yaffs_Device * dev) 822 { 823 return dev->rootDir; 824 } 825 826 yaffs_Object *yaffs_LostNFound(yaffs_Device * dev) 827 { 828 return dev->lostNFoundDir; 829 } 830 831 832 /* 833 * Erased NAND checking functions 834 */ 835 836 int yaffs_CheckFF(__u8 * buffer, int nBytes) 837 { 838 /* Horrible, slow implementation */ 839 while (nBytes--) { 840 if (*buffer != 0xFF) 841 return 0; 842 buffer++; 843 } 844 return 1; 845 } 846 847 static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, 848 int chunkInNAND) 849 { 850 851 int retval = YAFFS_OK; 852 __u8 *data = yaffs_GetTempBuffer(dev, __LINE__); 853 yaffs_ExtendedTags tags; 854 int result; 855 856 result = yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags); 857 858 if(tags.eccResult > YAFFS_ECC_RESULT_NO_ERROR) 859 retval = YAFFS_FAIL; 860 861 862 if (!yaffs_CheckFF(data, dev->nDataBytesPerChunk) || tags.chunkUsed) { 863 T(YAFFS_TRACE_NANDACCESS, 864 (TSTR("Chunk %d not erased" TENDSTR), chunkInNAND)); 865 retval = YAFFS_FAIL; 866 } 867 868 yaffs_ReleaseTempBuffer(dev, data, __LINE__); 869 870 return retval; 871 872 } 873 874 static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, 875 const __u8 * data, 876 yaffs_ExtendedTags * tags, 877 int useReserve) 878 { 879 int attempts = 0; 880 int writeOk = 0; 881 int chunk; 882 883 yaffs_InvalidateCheckpoint(dev); 884 885 do { 886 yaffs_BlockInfo *bi = 0; 887 int erasedOk = 0; 888 889 chunk = yaffs_AllocateChunk(dev, useReserve, &bi); 890 if (chunk < 0) { 891 /* no space */ 892 break; 893 } 894 895 /* First check this chunk is erased, if it needs 896 * checking. The checking policy (unless forced 897 * always on) is as follows: 898 * 899 * Check the first page we try to write in a block. 900 * If the check passes then we don't need to check any 901 * more. If the check fails, we check again... 902 * If the block has been erased, we don't need to check. 903 * 904 * However, if the block has been prioritised for gc, 905 * then we think there might be something odd about 906 * this block and stop using it. 907 * 908 * Rationale: We should only ever see chunks that have 909 * not been erased if there was a partially written 910 * chunk due to power loss. This checking policy should 911 * catch that case with very few checks and thus save a 912 * lot of checks that are most likely not needed. 913 */ 914 if (bi->gcPrioritise) { 915 yaffs_DeleteChunk(dev, chunk, 1, __LINE__); 916 /* try another chunk */ 917 continue; 918 } 919 920 /* let's give it a try */ 921 attempts++; 922 923 #ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED 924 bi->skipErasedCheck = 0; 925 #endif 926 if (!bi->skipErasedCheck) { 927 erasedOk = yaffs_CheckChunkErased(dev, chunk); 928 if (erasedOk != YAFFS_OK) { 929 T(YAFFS_TRACE_ERROR, 930 (TSTR ("**>> yaffs chunk %d was not erased" 931 TENDSTR), chunk)); 932 933 /* try another chunk */ 934 continue; 935 } 936 bi->skipErasedCheck = 1; 937 } 938 939 writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk, 940 data, tags); 941 if (writeOk != YAFFS_OK) { 942 yaffs_HandleWriteChunkError(dev, chunk, erasedOk); 943 /* try another chunk */ 944 continue; 945 } 946 947 /* Copy the data into the robustification buffer */ 948 yaffs_HandleWriteChunkOk(dev, chunk, data, tags); 949 950 } while (writeOk != YAFFS_OK && 951 (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts)); 952 953 if(!writeOk) 954 chunk = -1; 955 956 if (attempts > 1) { 957 T(YAFFS_TRACE_ERROR, 958 (TSTR("**>> yaffs write required %d attempts" TENDSTR), 959 attempts)); 960 961 dev->nRetriedWrites += (attempts - 1); 962 } 963 964 return chunk; 965 } 966 967 /* 968 * Block retiring for handling a broken block. 969 */ 970 971 static void yaffs_RetireBlock(yaffs_Device * dev, int blockInNAND) 972 { 973 yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND); 974 975 yaffs_InvalidateCheckpoint(dev); 976 977 yaffs_MarkBlockBad(dev, blockInNAND); 978 979 bi->blockState = YAFFS_BLOCK_STATE_DEAD; 980 bi->gcPrioritise = 0; 981 bi->needsRetiring = 0; 982 983 dev->nRetiredBlocks++; 984 } 985 986 /* 987 * Functions for robustisizing TODO 988 * 989 */ 990 991 static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND, 992 const __u8 * data, 993 const yaffs_ExtendedTags * tags) 994 { 995 } 996 997 static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND, 998 const yaffs_ExtendedTags * tags) 999 { 1000 } 1001 1002 void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi) 1003 { 1004 if(!bi->gcPrioritise){ 1005 bi->gcPrioritise = 1; 1006 dev->hasPendingPrioritisedGCs = 1; 1007 bi->chunkErrorStrikes ++; 1008 1009 if(bi->chunkErrorStrikes > 3){ 1010 bi->needsRetiring = 1; /* Too many stikes, so retire this */ 1011 T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR))); 1012 1013 } 1014 1015 } 1016 } 1017 1018 static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND, int erasedOk) 1019 { 1020 1021 int blockInNAND = chunkInNAND / dev->nChunksPerBlock; 1022 yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND); 1023 1024 yaffs_HandleChunkError(dev,bi); 1025 1026 1027 if(erasedOk ) { 1028 /* Was an actual write failure, so mark the block for retirement */ 1029 bi->needsRetiring = 1; 1030 T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, 1031 (TSTR("**>> Block %d needs retiring" TENDSTR), blockInNAND)); 1032 1033 1034 } 1035 1036 /* Delete the chunk */ 1037 yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__); 1038 } 1039 1040 1041 /*---------------- Name handling functions ------------*/ 1042 1043 static __u16 yaffs_CalcNameSum(const YCHAR * name) 1044 { 1045 __u16 sum = 0; 1046 __u16 i = 1; 1047 1048 YUCHAR *bname = (YUCHAR *) name; 1049 if (bname) { 1050 while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) { 1051 1052 #ifdef CONFIG_YAFFS_CASE_INSENSITIVE 1053 sum += yaffs_toupper(*bname) * i; 1054 #else 1055 sum += (*bname) * i; 1056 #endif 1057 i++; 1058 bname++; 1059 } 1060 } 1061 return sum; 1062 } 1063 1064 static void yaffs_SetObjectName(yaffs_Object * obj, const YCHAR * name) 1065 { 1066 #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM 1067 if (name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH) { 1068 yaffs_strcpy(obj->shortName, name); 1069 } else { 1070 obj->shortName[0] = _Y('\0'); 1071 } 1072 #endif 1073 obj->sum = yaffs_CalcNameSum(name); 1074 } 1075 1076 /*-------------------- TNODES ------------------- 1077 1078 * List of spare tnodes 1079 * The list is hooked together using the first pointer 1080 * in the tnode. 1081 */ 1082 1083 /* yaffs_CreateTnodes creates a bunch more tnodes and 1084 * adds them to the tnode free list. 1085 * Don't use this function directly 1086 */ 1087 1088 static int yaffs_CreateTnodes(yaffs_Device * dev, int nTnodes) 1089 { 1090 int i; 1091 int tnodeSize; 1092 yaffs_Tnode *newTnodes; 1093 __u8 *mem; 1094 yaffs_Tnode *curr; 1095 yaffs_Tnode *next; 1096 yaffs_TnodeList *tnl; 1097 1098 if (nTnodes < 1) 1099 return YAFFS_OK; 1100 1101 /* Calculate the tnode size in bytes for variable width tnode support. 1102 * Must be a multiple of 32-bits */ 1103 tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; 1104 1105 /* make these things */ 1106 1107 newTnodes = YMALLOC(nTnodes * tnodeSize); 1108 mem = (__u8 *)newTnodes; 1109 1110 if (!newTnodes) { 1111 T(YAFFS_TRACE_ERROR, 1112 (TSTR("yaffs: Could not allocate Tnodes" TENDSTR))); 1113 return YAFFS_FAIL; 1114 } 1115 1116 /* Hook them into the free list */ 1117 #if 0 1118 for (i = 0; i < nTnodes - 1; i++) { 1119 newTnodes[i].internal[0] = &newTnodes[i + 1]; 1120 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG 1121 newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = (void *)1; 1122 #endif 1123 } 1124 1125 newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes; 1126 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG 1127 newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = (void *)1; 1128 #endif 1129 dev->freeTnodes = newTnodes; 1130 #else 1131 /* New hookup for wide tnodes */ 1132 for(i = 0; i < nTnodes -1; i++) { 1133 curr = (yaffs_Tnode *) &mem[i * tnodeSize]; 1134 next = (yaffs_Tnode *) &mem[(i+1) * tnodeSize]; 1135 curr->internal[0] = next; 1136 } 1137 1138 curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * tnodeSize]; 1139 curr->internal[0] = dev->freeTnodes; 1140 dev->freeTnodes = (yaffs_Tnode *)mem; 1141 1142 #endif 1143 1144 1145 dev->nFreeTnodes += nTnodes; 1146 dev->nTnodesCreated += nTnodes; 1147 1148 /* Now add this bunch of tnodes to a list for freeing up. 1149 * NB If we can't add this to the management list it isn't fatal 1150 * but it just means we can't free this bunch of tnodes later. 1151 */ 1152 1153 tnl = YMALLOC(sizeof(yaffs_TnodeList)); 1154 if (!tnl) { 1155 T(YAFFS_TRACE_ERROR, 1156 (TSTR 1157 ("yaffs: Could not add tnodes to management list" TENDSTR))); 1158 return YAFFS_FAIL; 1159 1160 } else { 1161 tnl->tnodes = newTnodes; 1162 tnl->next = dev->allocatedTnodeList; 1163 dev->allocatedTnodeList = tnl; 1164 } 1165 1166 T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR))); 1167 1168 return YAFFS_OK; 1169 } 1170 1171 /* GetTnode gets us a clean tnode. Tries to make allocate more if we run out */ 1172 1173 static yaffs_Tnode *yaffs_GetTnodeRaw(yaffs_Device * dev) 1174 { 1175 yaffs_Tnode *tn = NULL; 1176 1177 /* If there are none left make more */ 1178 if (!dev->freeTnodes) { 1179 yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES); 1180 } 1181 1182 if (dev->freeTnodes) { 1183 tn = dev->freeTnodes; 1184 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG 1185 if (tn->internal[YAFFS_NTNODES_INTERNAL] != (void *)1) { 1186 /* Hoosterman, this thing looks like it isn't in the list */ 1187 T(YAFFS_TRACE_ALWAYS, 1188 (TSTR("yaffs: Tnode list bug 1" TENDSTR))); 1189 } 1190 #endif 1191 dev->freeTnodes = dev->freeTnodes->internal[0]; 1192 dev->nFreeTnodes--; 1193 } 1194 1195 return tn; 1196 } 1197 1198 static yaffs_Tnode *yaffs_GetTnode(yaffs_Device * dev) 1199 { 1200 yaffs_Tnode *tn = yaffs_GetTnodeRaw(dev); 1201 1202 if(tn) 1203 memset(tn, 0, (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8); 1204 1205 return tn; 1206 } 1207 1208 /* FreeTnode frees up a tnode and puts it back on the free list */ 1209 static void yaffs_FreeTnode(yaffs_Device * dev, yaffs_Tnode * tn) 1210 { 1211 if (tn) { 1212 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG 1213 if (tn->internal[YAFFS_NTNODES_INTERNAL] != 0) { 1214 /* Hoosterman, this thing looks like it is already in the list */ 1215 T(YAFFS_TRACE_ALWAYS, 1216 (TSTR("yaffs: Tnode list bug 2" TENDSTR))); 1217 } 1218 tn->internal[YAFFS_NTNODES_INTERNAL] = (void *)1; 1219 #endif 1220 tn->internal[0] = dev->freeTnodes; 1221 dev->freeTnodes = tn; 1222 dev->nFreeTnodes++; 1223 } 1224 } 1225 1226 static void yaffs_DeinitialiseTnodes(yaffs_Device * dev) 1227 { 1228 /* Free the list of allocated tnodes */ 1229 yaffs_TnodeList *tmp; 1230 1231 while (dev->allocatedTnodeList) { 1232 tmp = dev->allocatedTnodeList->next; 1233 1234 YFREE(dev->allocatedTnodeList->tnodes); 1235 YFREE(dev->allocatedTnodeList); 1236 dev->allocatedTnodeList = tmp; 1237 1238 } 1239 1240 dev->freeTnodes = NULL; 1241 dev->nFreeTnodes = 0; 1242 } 1243 1244 static void yaffs_InitialiseTnodes(yaffs_Device * dev) 1245 { 1246 dev->allocatedTnodeList = NULL; 1247 dev->freeTnodes = NULL; 1248 dev->nFreeTnodes = 0; 1249 dev->nTnodesCreated = 0; 1250 1251 } 1252 1253 1254 void yaffs_PutLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos, unsigned val) 1255 { 1256 __u32 *map = (__u32 *)tn; 1257 __u32 bitInMap; 1258 __u32 bitInWord; 1259 __u32 wordInMap; 1260 __u32 mask; 1261 1262 pos &= YAFFS_TNODES_LEVEL0_MASK; 1263 val >>= dev->chunkGroupBits; 1264 1265 bitInMap = pos * dev->tnodeWidth; 1266 wordInMap = bitInMap /32; 1267 bitInWord = bitInMap & (32 -1); 1268 1269 mask = dev->tnodeMask << bitInWord; 1270 1271 map[wordInMap] &= ~mask; 1272 map[wordInMap] |= (mask & (val << bitInWord)); 1273 1274 if(dev->tnodeWidth > (32-bitInWord)) { 1275 bitInWord = (32 - bitInWord); 1276 wordInMap++;; 1277 mask = dev->tnodeMask >> (/*dev->tnodeWidth -*/ bitInWord); 1278 map[wordInMap] &= ~mask; 1279 map[wordInMap] |= (mask & (val >> bitInWord)); 1280 } 1281 } 1282 1283 static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos) 1284 { 1285 __u32 *map = (__u32 *)tn; 1286 __u32 bitInMap; 1287 __u32 bitInWord; 1288 __u32 wordInMap; 1289 __u32 val; 1290 1291 pos &= YAFFS_TNODES_LEVEL0_MASK; 1292 1293 bitInMap = pos * dev->tnodeWidth; 1294 wordInMap = bitInMap /32; 1295 bitInWord = bitInMap & (32 -1); 1296 1297 val = map[wordInMap] >> bitInWord; 1298 1299 if(dev->tnodeWidth > (32-bitInWord)) { 1300 bitInWord = (32 - bitInWord); 1301 wordInMap++;; 1302 val |= (map[wordInMap] << bitInWord); 1303 } 1304 1305 val &= dev->tnodeMask; 1306 val <<= dev->chunkGroupBits; 1307 1308 return val; 1309 } 1310 1311 /* ------------------- End of individual tnode manipulation -----------------*/ 1312 1313 /* ---------Functions to manipulate the look-up tree (made up of tnodes) ------ 1314 * The look up tree is represented by the top tnode and the number of topLevel 1315 * in the tree. 0 means only the level 0 tnode is in the tree. 1316 */ 1317 1318 /* FindLevel0Tnode finds the level 0 tnode, if one exists. */ 1319 static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device * dev, 1320 yaffs_FileStructure * fStruct, 1321 __u32 chunkId) 1322 { 1323 1324 yaffs_Tnode *tn = fStruct->top; 1325 __u32 i; 1326 int requiredTallness; 1327 int level = fStruct->topLevel; 1328 1329 /* Check sane level and chunk Id */ 1330 if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL) { 1331 return NULL; 1332 } 1333 1334 if (chunkId > YAFFS_MAX_CHUNK_ID) { 1335 return NULL; 1336 } 1337 1338 /* First check we're tall enough (ie enough topLevel) */ 1339 1340 i = chunkId >> YAFFS_TNODES_LEVEL0_BITS; 1341 requiredTallness = 0; 1342 while (i) { 1343 i >>= YAFFS_TNODES_INTERNAL_BITS; 1344 requiredTallness++; 1345 } 1346 1347 if (requiredTallness > fStruct->topLevel) { 1348 /* Not tall enough, so we can't find it, return NULL. */ 1349 return NULL; 1350 } 1351 1352 /* Traverse down to level 0 */ 1353 while (level > 0 && tn) { 1354 tn = tn-> 1355 internal[(chunkId >> 1356 ( YAFFS_TNODES_LEVEL0_BITS + 1357 (level - 1) * 1358 YAFFS_TNODES_INTERNAL_BITS) 1359 ) & 1360 YAFFS_TNODES_INTERNAL_MASK]; 1361 level--; 1362 1363 } 1364 1365 return tn; 1366 } 1367 1368 /* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree. 1369 * This happens in two steps: 1370 * 1. If the tree isn't tall enough, then make it taller. 1371 * 2. Scan down the tree towards the level 0 tnode adding tnodes if required. 1372 * 1373 * Used when modifying the tree. 1374 * 1375 * If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will 1376 * be plugged into the ttree. 1377 */ 1378 1379 static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device * dev, 1380 yaffs_FileStructure * fStruct, 1381 __u32 chunkId, 1382 yaffs_Tnode *passedTn) 1383 { 1384 1385 int requiredTallness; 1386 int i; 1387 int l; 1388 yaffs_Tnode *tn; 1389 1390 __u32 x; 1391 1392 1393 /* Check sane level and page Id */ 1394 if (fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL) { 1395 return NULL; 1396 } 1397 1398 if (chunkId > YAFFS_MAX_CHUNK_ID) { 1399 return NULL; 1400 } 1401 1402 /* First check we're tall enough (ie enough topLevel) */ 1403 1404 x = chunkId >> YAFFS_TNODES_LEVEL0_BITS; 1405 requiredTallness = 0; 1406 while (x) { 1407 x >>= YAFFS_TNODES_INTERNAL_BITS; 1408 requiredTallness++; 1409 } 1410 1411 1412 if (requiredTallness > fStruct->topLevel) { 1413 /* Not tall enough,gotta make the tree taller */ 1414 for (i = fStruct->topLevel; i < requiredTallness; i++) { 1415 1416 tn = yaffs_GetTnode(dev); 1417 1418 if (tn) { 1419 tn->internal[0] = fStruct->top; 1420 fStruct->top = tn; 1421 } else { 1422 T(YAFFS_TRACE_ERROR, 1423 (TSTR("yaffs: no more tnodes" TENDSTR))); 1424 } 1425 } 1426 1427 fStruct->topLevel = requiredTallness; 1428 } 1429 1430 /* Traverse down to level 0, adding anything we need */ 1431 1432 l = fStruct->topLevel; 1433 tn = fStruct->top; 1434 1435 if(l > 0) { 1436 while (l > 0 && tn) { 1437 x = (chunkId >> 1438 ( YAFFS_TNODES_LEVEL0_BITS + 1439 (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) & 1440 YAFFS_TNODES_INTERNAL_MASK; 1441 1442 1443 if((l>1) && !tn->internal[x]){ 1444 /* Add missing non-level-zero tnode */ 1445 tn->internal[x] = yaffs_GetTnode(dev); 1446 1447 } else if(l == 1) { 1448 /* Looking from level 1 at level 0 */ 1449 if (passedTn) { 1450 /* If we already have one, then release it.*/ 1451 if(tn->internal[x]) 1452 yaffs_FreeTnode(dev,tn->internal[x]); 1453 tn->internal[x] = passedTn; 1454 1455 } else if(!tn->internal[x]) { 1456 /* Don't have one, none passed in */ 1457 tn->internal[x] = yaffs_GetTnode(dev); 1458 } 1459 } 1460 1461 tn = tn->internal[x]; 1462 l--; 1463 } 1464 } else { 1465 /* top is level 0 */ 1466 if(passedTn) { 1467 memcpy(tn,passedTn,(dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8); 1468 yaffs_FreeTnode(dev,passedTn); 1469 } 1470 } 1471 1472 return tn; 1473 } 1474 1475 static int yaffs_FindChunkInGroup(yaffs_Device * dev, int theChunk, 1476 yaffs_ExtendedTags * tags, int objectId, 1477 int chunkInInode) 1478 { 1479 int j; 1480 1481 for (j = 0; theChunk && j < dev->chunkGroupSize; j++) { 1482 if (yaffs_CheckChunkBit 1483 (dev, theChunk / dev->nChunksPerBlock, 1484 theChunk % dev->nChunksPerBlock)) { 1485 yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, 1486 tags); 1487 if (yaffs_TagsMatch(tags, objectId, chunkInInode)) { 1488 /* found it; */ 1489 return theChunk; 1490 1491 } 1492 } 1493 theChunk++; 1494 } 1495 return -1; 1496 } 1497 1498 static void yaffs_SoftDeleteChunk(yaffs_Device * dev, int chunk) 1499 { 1500 1501 yaffs_BlockInfo *theBlock; 1502 1503 T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk)); 1504 1505 theBlock = yaffs_GetBlockInfo(dev, chunk / dev->nChunksPerBlock); 1506 if (theBlock) { 1507 theBlock->softDeletions++; 1508 dev->nFreeChunks++; 1509 } 1510 } 1511 1512 /* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file. 1513 * All soft deleting does is increment the block's softdelete count and pulls the chunk out 1514 * of the tnode. 1515 * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted. 1516 */ 1517 1518 static int yaffs_SoftDeleteWorker(yaffs_Object * in, yaffs_Tnode * tn, 1519 __u32 level, int chunkOffset) 1520 { 1521 int i; 1522 int theChunk; 1523 int allDone = 1; 1524 yaffs_Device *dev = in->myDev; 1525 1526 if (tn) { 1527 if (level > 0) { 1528 1529 for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0; 1530 i--) { 1531 if (tn->internal[i]) { 1532 allDone = 1533 yaffs_SoftDeleteWorker(in, 1534 tn-> 1535 internal[i], 1536 level - 1, 1537 (chunkOffset 1538 << 1539 YAFFS_TNODES_INTERNAL_BITS) 1540 + i); 1541 if (allDone) { 1542 yaffs_FreeTnode(dev, 1543 tn-> 1544 internal[i]); 1545 tn->internal[i] = NULL; 1546 } else { 1547 /* Hoosterman... how could this happen? */ 1548 } 1549 } 1550 } 1551 return (allDone) ? 1 : 0; 1552 } else if (level == 0) { 1553 1554 for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) { 1555 theChunk = yaffs_GetChunkGroupBase(dev,tn,i); 1556 if (theChunk) { 1557 /* Note this does not find the real chunk, only the chunk group. 1558 * We make an assumption that a chunk group is not larger than 1559 * a block. 1560 */ 1561 yaffs_SoftDeleteChunk(dev, theChunk); 1562 yaffs_PutLevel0Tnode(dev,tn,i,0); 1563 } 1564 1565 } 1566 return 1; 1567 1568 } 1569 1570 } 1571 1572 return 1; 1573 1574 } 1575 1576 static void yaffs_SoftDeleteFile(yaffs_Object * obj) 1577 { 1578 if (obj->deleted && 1579 obj->variantType == YAFFS_OBJECT_TYPE_FILE && !obj->softDeleted) { 1580 if (obj->nDataChunks <= 0) { 1581 /* Empty file with no duplicate object headers, just delete it immediately */ 1582 yaffs_FreeTnode(obj->myDev, 1583 obj->variant.fileVariant.top); 1584 obj->variant.fileVariant.top = NULL; 1585 T(YAFFS_TRACE_TRACING, 1586 (TSTR("yaffs: Deleting empty file %d" TENDSTR), 1587 obj->objectId)); 1588 yaffs_DoGenericObjectDeletion(obj); 1589 } else { 1590 yaffs_SoftDeleteWorker(obj, 1591 obj->variant.fileVariant.top, 1592 obj->variant.fileVariant. 1593 topLevel, 0); 1594 obj->softDeleted = 1; 1595 } 1596 } 1597 } 1598 1599 /* Pruning removes any part of the file structure tree that is beyond the 1600 * bounds of the file (ie that does not point to chunks). 1601 * 1602 * A file should only get pruned when its size is reduced. 1603 * 1604 * Before pruning, the chunks must be pulled from the tree and the 1605 * level 0 tnode entries must be zeroed out. 1606 * Could also use this for file deletion, but that's probably better handled 1607 * by a special case. 1608 */ 1609 1610 static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device * dev, yaffs_Tnode * tn, 1611 __u32 level, int del0) 1612 { 1613 int i; 1614 int hasData; 1615 1616 if (tn) { 1617 hasData = 0; 1618 1619 for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) { 1620 if (tn->internal[i] && level > 0) { 1621 tn->internal[i] = 1622 yaffs_PruneWorker(dev, tn->internal[i], 1623 level - 1, 1624 (i == 0) ? del0 : 1); 1625 } 1626 1627 if (tn->internal[i]) { 1628 hasData++; 1629 } 1630 } 1631 1632 if (hasData == 0 && del0) { 1633 /* Free and return NULL */ 1634 1635 yaffs_FreeTnode(dev, tn); 1636 tn = NULL; 1637 } 1638 1639 } 1640 1641 return tn; 1642 1643 } 1644 1645 static int yaffs_PruneFileStructure(yaffs_Device * dev, 1646 yaffs_FileStructure * fStruct) 1647 { 1648 int i; 1649 int hasData; 1650 int done = 0; 1651 yaffs_Tnode *tn; 1652 1653 if (fStruct->topLevel > 0) { 1654 fStruct->top = 1655 yaffs_PruneWorker(dev, fStruct->top, fStruct->topLevel, 0); 1656 1657 /* Now we have a tree with all the non-zero branches NULL but the height 1658 * is the same as it was. 1659 * Let's see if we can trim internal tnodes to shorten the tree. 1660 * We can do this if only the 0th element in the tnode is in use 1661 * (ie all the non-zero are NULL) 1662 */ 1663 1664 while (fStruct->topLevel && !done) { 1665 tn = fStruct->top; 1666 1667 hasData = 0; 1668 for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) { 1669 if (tn->internal[i]) { 1670 hasData++; 1671 } 1672 } 1673 1674 if (!hasData) { 1675 fStruct->top = tn->internal[0]; 1676 fStruct->topLevel--; 1677 yaffs_FreeTnode(dev, tn); 1678 } else { 1679 done = 1; 1680 } 1681 } 1682 } 1683 1684 return YAFFS_OK; 1685 } 1686 1687 /*-------------------- End of File Structure functions.-------------------*/ 1688 1689 /* yaffs_CreateFreeObjects creates a bunch more objects and 1690 * adds them to the object free list. 1691 */ 1692 static int yaffs_CreateFreeObjects(yaffs_Device * dev, int nObjects) 1693 { 1694 int i; 1695 yaffs_Object *newObjects; 1696 yaffs_ObjectList *list; 1697 1698 if (nObjects < 1) 1699 return YAFFS_OK; 1700 1701 /* make these things */ 1702 newObjects = YMALLOC(nObjects * sizeof(yaffs_Object)); 1703 list = YMALLOC(sizeof(yaffs_ObjectList)); 1704 1705 if (!newObjects || !list) { 1706 if(newObjects) 1707 YFREE(newObjects); 1708 if(list) 1709 YFREE(list); 1710 T(YAFFS_TRACE_ALLOCATE, 1711 (TSTR("yaffs: Could not allocate more objects" TENDSTR))); 1712 return YAFFS_FAIL; 1713 } 1714 1715 /* Hook them into the free list */ 1716 for (i = 0; i < nObjects - 1; i++) { 1717 newObjects[i].siblings.next = 1718 (struct list_head *)(&newObjects[i + 1]); 1719 } 1720 1721 newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects; 1722 dev->freeObjects = newObjects; 1723 dev->nFreeObjects += nObjects; 1724 dev->nObjectsCreated += nObjects; 1725 1726 /* Now add this bunch of Objects to a list for freeing up. */ 1727 1728 list->objects = newObjects; 1729 list->next = dev->allocatedObjectList; 1730 dev->allocatedObjectList = list; 1731 1732 return YAFFS_OK; 1733 } 1734 1735 1736 /* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */ 1737 static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device * dev) 1738 { 1739 yaffs_Object *tn = NULL; 1740 1741 /* If there are none left make more */ 1742 if (!dev->freeObjects) { 1743 yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS); 1744 } 1745 1746 if (dev->freeObjects) { 1747 tn = dev->freeObjects; 1748 dev->freeObjects = 1749 (yaffs_Object *) (dev->freeObjects->siblings.next); 1750 dev->nFreeObjects--; 1751 1752 /* Now sweeten it up... */ 1753 1754 memset(tn, 0, sizeof(yaffs_Object)); 1755 tn->myDev = dev; 1756 tn->chunkId = -1; 1757 tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN; 1758 INIT_LIST_HEAD(&(tn->hardLinks)); 1759 INIT_LIST_HEAD(&(tn->hashLink)); 1760 INIT_LIST_HEAD(&tn->siblings); 1761 1762 /* Add it to the lost and found directory. 1763 * NB Can't put root or lostNFound in lostNFound so 1764 * check if lostNFound exists first 1765 */ 1766 if (dev->lostNFoundDir) { 1767 yaffs_AddObjectToDirectory(dev->lostNFoundDir, tn); 1768 } 1769 } 1770 1771 return tn; 1772 } 1773 1774 static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device * dev, int number, 1775 __u32 mode) 1776 { 1777 1778 yaffs_Object *obj = 1779 yaffs_CreateNewObject(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY); 1780 if (obj) { 1781 obj->fake = 1; /* it is fake so it has no NAND presence... */ 1782 obj->renameAllowed = 0; /* ... and we're not allowed to rename it... */ 1783 obj->unlinkAllowed = 0; /* ... or unlink it */ 1784 obj->deleted = 0; 1785 obj->unlinked = 0; 1786 obj->yst_mode = mode; 1787 obj->myDev = dev; 1788 obj->chunkId = 0; /* Not a valid chunk. */ 1789 } 1790 1791 return obj; 1792 1793 } 1794 1795 static void yaffs_UnhashObject(yaffs_Object * tn) 1796 { 1797 int bucket; 1798 yaffs_Device *dev = tn->myDev; 1799 1800 /* If it is still linked into the bucket list, free from the list */ 1801 if (!list_empty(&tn->hashLink)) { 1802 list_del_init(&tn->hashLink); 1803 bucket = yaffs_HashFunction(tn->objectId); 1804 dev->objectBucket[bucket].count--; 1805 } 1806 1807 } 1808 1809 /* FreeObject frees up a Object and puts it back on the free list */ 1810 static void yaffs_FreeObject(yaffs_Object * tn) 1811 { 1812 1813 yaffs_Device *dev = tn->myDev; 1814 1815 /* XXX U-BOOT XXX */ 1816 #if 0 1817 #ifdef __KERNEL__ 1818 if (tn->myInode) { 1819 /* We're still hooked up to a cached inode. 1820 * Don't delete now, but mark for later deletion 1821 */ 1822 tn->deferedFree = 1; 1823 return; 1824 } 1825 #endif 1826 #endif 1827 yaffs_UnhashObject(tn); 1828 1829 /* Link into the free list. */ 1830 tn->siblings.next = (struct list_head *)(dev->freeObjects); 1831 dev->freeObjects = tn; 1832 dev->nFreeObjects++; 1833 } 1834 1835 /* XXX U-BOOT XXX */ 1836 #if 0 1837 #ifdef __KERNEL__ 1838 1839 void yaffs_HandleDeferedFree(yaffs_Object * obj) 1840 { 1841 if (obj->deferedFree) { 1842 yaffs_FreeObject(obj); 1843 } 1844 } 1845 1846 #endif 1847 #endif 1848 1849 static void yaffs_DeinitialiseObjects(yaffs_Device * dev) 1850 { 1851 /* Free the list of allocated Objects */ 1852 1853 yaffs_ObjectList *tmp; 1854 1855 while (dev->allocatedObjectList) { 1856 tmp = dev->allocatedObjectList->next; 1857 YFREE(dev->allocatedObjectList->objects); 1858 YFREE(dev->allocatedObjectList); 1859 1860 dev->allocatedObjectList = tmp; 1861 } 1862 1863 dev->freeObjects = NULL; 1864 dev->nFreeObjects = 0; 1865 } 1866 1867 static void yaffs_InitialiseObjects(yaffs_Device * dev) 1868 { 1869 int i; 1870 1871 dev->allocatedObjectList = NULL; 1872 dev->freeObjects = NULL; 1873 dev->nFreeObjects = 0; 1874 1875 for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { 1876 INIT_LIST_HEAD(&dev->objectBucket[i].list); 1877 dev->objectBucket[i].count = 0; 1878 } 1879 1880 } 1881 1882 static int yaffs_FindNiceObjectBucket(yaffs_Device * dev) 1883 { 1884 static int x = 0; 1885 int i; 1886 int l = 999; 1887 int lowest = 999999; 1888 1889 /* First let's see if we can find one that's empty. */ 1890 1891 for (i = 0; i < 10 && lowest > 0; i++) { 1892 x++; 1893 x %= YAFFS_NOBJECT_BUCKETS; 1894 if (dev->objectBucket[x].count < lowest) { 1895 lowest = dev->objectBucket[x].count; 1896 l = x; 1897 } 1898 1899 } 1900 1901 /* If we didn't find an empty list, then try 1902 * looking a bit further for a short one 1903 */ 1904 1905 for (i = 0; i < 10 && lowest > 3; i++) { 1906 x++; 1907 x %= YAFFS_NOBJECT_BUCKETS; 1908 if (dev->objectBucket[x].count < lowest) { 1909 lowest = dev->objectBucket[x].count; 1910 l = x; 1911 } 1912 1913 } 1914 1915 return l; 1916 } 1917 1918 static int yaffs_CreateNewObjectNumber(yaffs_Device * dev) 1919 { 1920 int bucket = yaffs_FindNiceObjectBucket(dev); 1921 1922 /* Now find an object value that has not already been taken 1923 * by scanning the list. 1924 */ 1925 1926 int found = 0; 1927 struct list_head *i; 1928 1929 __u32 n = (__u32) bucket; 1930 1931 /* yaffs_CheckObjectHashSanity(); */ 1932 1933 while (!found) { 1934 found = 1; 1935 n += YAFFS_NOBJECT_BUCKETS; 1936 if (1 || dev->objectBucket[bucket].count > 0) { 1937 list_for_each(i, &dev->objectBucket[bucket].list) { 1938 /* If there is already one in the list */ 1939 if (i 1940 && list_entry(i, yaffs_Object, 1941 hashLink)->objectId == n) { 1942 found = 0; 1943 } 1944 } 1945 } 1946 } 1947 1948 1949 return n; 1950 } 1951 1952 static void yaffs_HashObject(yaffs_Object * in) 1953 { 1954 int bucket = yaffs_HashFunction(in->objectId); 1955 yaffs_Device *dev = in->myDev; 1956 1957 list_add(&in->hashLink, &dev->objectBucket[bucket].list); 1958 dev->objectBucket[bucket].count++; 1959 1960 } 1961 1962 yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device * dev, __u32 number) 1963 { 1964 int bucket = yaffs_HashFunction(number); 1965 struct list_head *i; 1966 yaffs_Object *in; 1967 1968 list_for_each(i, &dev->objectBucket[bucket].list) { 1969 /* Look if it is in the list */ 1970 if (i) { 1971 in = list_entry(i, yaffs_Object, hashLink); 1972 if (in->objectId == number) { 1973 /* XXX U-BOOT XXX */ 1974 #if 0 1975 #ifdef __KERNEL__ 1976 /* Don't tell the VFS about this one if it is defered free */ 1977 if (in->deferedFree) 1978 return NULL; 1979 #endif 1980 #endif 1981 return in; 1982 } 1983 } 1984 } 1985 1986 return NULL; 1987 } 1988 1989 yaffs_Object *yaffs_CreateNewObject(yaffs_Device * dev, int number, 1990 yaffs_ObjectType type) 1991 { 1992 1993 yaffs_Object *theObject; 1994 yaffs_Tnode *tn = NULL; 1995 1996 if (number < 0) { 1997 number = yaffs_CreateNewObjectNumber(dev); 1998 } 1999 2000 theObject = yaffs_AllocateEmptyObject(dev); 2001 if(!theObject) 2002 return NULL; 2003 2004 if(type == YAFFS_OBJECT_TYPE_FILE){ 2005 tn = yaffs_GetTnode(dev); 2006 if(!tn){ 2007 yaffs_FreeObject(theObject); 2008 return NULL; 2009 } 2010 } 2011 2012 2013 2014 if (theObject) { 2015 theObject->fake = 0; 2016 theObject->renameAllowed = 1; 2017 theObject->unlinkAllowed = 1; 2018 theObject->objectId = number; 2019 yaffs_HashObject(theObject); 2020 theObject->variantType = type; 2021 #ifdef CONFIG_YAFFS_WINCE 2022 yfsd_WinFileTimeNow(theObject->win_atime); 2023 theObject->win_ctime[0] = theObject->win_mtime[0] = 2024 theObject->win_atime[0]; 2025 theObject->win_ctime[1] = theObject->win_mtime[1] = 2026 theObject->win_atime[1]; 2027 2028 #else 2029 2030 theObject->yst_atime = theObject->yst_mtime = 2031 theObject->yst_ctime = Y_CURRENT_TIME; 2032 #endif 2033 switch (type) { 2034 case YAFFS_OBJECT_TYPE_FILE: 2035 theObject->variant.fileVariant.fileSize = 0; 2036 theObject->variant.fileVariant.scannedFileSize = 0; 2037 theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; /* max __u32 */ 2038 theObject->variant.fileVariant.topLevel = 0; 2039 theObject->variant.fileVariant.top = tn; 2040 break; 2041 case YAFFS_OBJECT_TYPE_DIRECTORY: 2042 INIT_LIST_HEAD(&theObject->variant.directoryVariant. 2043 children); 2044 break; 2045 case YAFFS_OBJECT_TYPE_SYMLINK: 2046 case YAFFS_OBJECT_TYPE_HARDLINK: 2047 case YAFFS_OBJECT_TYPE_SPECIAL: 2048 /* No action required */ 2049 break; 2050 case YAFFS_OBJECT_TYPE_UNKNOWN: 2051 /* todo this should not happen */ 2052 break; 2053 } 2054 } 2055 2056 return theObject; 2057 } 2058 2059 static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device * dev, 2060 int number, 2061 yaffs_ObjectType type) 2062 { 2063 yaffs_Object *theObject = NULL; 2064 2065 if (number > 0) { 2066 theObject = yaffs_FindObjectByNumber(dev, number); 2067 } 2068 2069 if (!theObject) { 2070 theObject = yaffs_CreateNewObject(dev, number, type); 2071 } 2072 2073 return theObject; 2074 2075 } 2076 2077 2078 static YCHAR *yaffs_CloneString(const YCHAR * str) 2079 { 2080 YCHAR *newStr = NULL; 2081 2082 if (str && *str) { 2083 newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR)); 2084 if(newStr) 2085 yaffs_strcpy(newStr, str); 2086 } 2087 2088 return newStr; 2089 2090 } 2091 2092 /* 2093 * Mknod (create) a new object. 2094 * equivalentObject only has meaning for a hard link; 2095 * aliasString only has meaning for a sumlink. 2096 * rdev only has meaning for devices (a subset of special objects) 2097 */ 2098 2099 static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type, 2100 yaffs_Object * parent, 2101 const YCHAR * name, 2102 __u32 mode, 2103 __u32 uid, 2104 __u32 gid, 2105 yaffs_Object * equivalentObject, 2106 const YCHAR * aliasString, __u32 rdev) 2107 { 2108 yaffs_Object *in; 2109 YCHAR *str = NULL; 2110 2111 yaffs_Device *dev = parent->myDev; 2112 2113 /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/ 2114 if (yaffs_FindObjectByName(parent, name)) { 2115 return NULL; 2116 } 2117 2118 in = yaffs_CreateNewObject(dev, -1, type); 2119 2120 if(type == YAFFS_OBJECT_TYPE_SYMLINK){ 2121 str = yaffs_CloneString(aliasString); 2122 if(!str){ 2123 yaffs_FreeObject(in); 2124 return NULL; 2125 } 2126 } 2127 2128 2129 2130 if (in) { 2131 in->chunkId = -1; 2132 in->valid = 1; 2133 in->variantType = type; 2134 2135 in->yst_mode = mode; 2136 2137 #ifdef CONFIG_YAFFS_WINCE 2138 yfsd_WinFileTimeNow(in->win_atime); 2139 in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0]; 2140 in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1]; 2141 2142 #else 2143 in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME; 2144 2145 in->yst_rdev = rdev; 2146 in->yst_uid = uid; 2147 in->yst_gid = gid; 2148 #endif 2149 in->nDataChunks = 0; 2150 2151 yaffs_SetObjectName(in, name); 2152 in->dirty = 1; 2153 2154 yaffs_AddObjectToDirectory(parent, in); 2155 2156 in->myDev = parent->myDev; 2157 2158 switch (type) { 2159 case YAFFS_OBJECT_TYPE_SYMLINK: 2160 in->variant.symLinkVariant.alias = str; 2161 break; 2162 case YAFFS_OBJECT_TYPE_HARDLINK: 2163 in->variant.hardLinkVariant.equivalentObject = 2164 equivalentObject; 2165 in->variant.hardLinkVariant.equivalentObjectId = 2166 equivalentObject->objectId; 2167 list_add(&in->hardLinks, &equivalentObject->hardLinks); 2168 break; 2169 case YAFFS_OBJECT_TYPE_FILE: 2170 case YAFFS_OBJECT_TYPE_DIRECTORY: 2171 case YAFFS_OBJECT_TYPE_SPECIAL: 2172 case YAFFS_OBJECT_TYPE_UNKNOWN: 2173 /* do nothing */ 2174 break; 2175 } 2176 2177 if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0) < 0) { 2178 /* Could not create the object header, fail the creation */ 2179 yaffs_DestroyObject(in); 2180 in = NULL; 2181 } 2182 2183 } 2184 2185 return in; 2186 } 2187 2188 yaffs_Object *yaffs_MknodFile(yaffs_Object * parent, const YCHAR * name, 2189 __u32 mode, __u32 uid, __u32 gid) 2190 { 2191 return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE, parent, name, mode, 2192 uid, gid, NULL, NULL, 0); 2193 } 2194 2195 yaffs_Object *yaffs_MknodDirectory(yaffs_Object * parent, const YCHAR * name, 2196 __u32 mode, __u32 uid, __u32 gid) 2197 { 2198 return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name, 2199 mode, uid, gid, NULL, NULL, 0); 2200 } 2201 2202 yaffs_Object *yaffs_MknodSpecial(yaffs_Object * parent, const YCHAR * name, 2203 __u32 mode, __u32 uid, __u32 gid, __u32 rdev) 2204 { 2205 return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode, 2206 uid, gid, NULL, NULL, rdev); 2207 } 2208 2209 yaffs_Object *yaffs_MknodSymLink(yaffs_Object * parent, const YCHAR * name, 2210 __u32 mode, __u32 uid, __u32 gid, 2211 const YCHAR * alias) 2212 { 2213 return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode, 2214 uid, gid, NULL, alias, 0); 2215 } 2216 2217 /* yaffs_Link returns the object id of the equivalent object.*/ 2218 yaffs_Object *yaffs_Link(yaffs_Object * parent, const YCHAR * name, 2219 yaffs_Object * equivalentObject) 2220 { 2221 /* Get the real object in case we were fed a hard link as an equivalent object */ 2222 equivalentObject = yaffs_GetEquivalentObject(equivalentObject); 2223 2224 if (yaffs_MknodObject 2225 (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0, 2226 equivalentObject, NULL, 0)) { 2227 return equivalentObject; 2228 } else { 2229 return NULL; 2230 } 2231 2232 } 2233 2234 static int yaffs_ChangeObjectName(yaffs_Object * obj, yaffs_Object * newDir, 2235 const YCHAR * newName, int force, int shadows) 2236 { 2237 int unlinkOp; 2238 int deleteOp; 2239 2240 yaffs_Object *existingTarget; 2241 2242 if (newDir == NULL) { 2243 newDir = obj->parent; /* use the old directory */ 2244 } 2245 2246 if (newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { 2247 T(YAFFS_TRACE_ALWAYS, 2248 (TSTR 2249 ("tragendy: yaffs_ChangeObjectName: newDir is not a directory" 2250 TENDSTR))); 2251 YBUG(); 2252 } 2253 2254 /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */ 2255 if (obj->myDev->isYaffs2) { 2256 unlinkOp = (newDir == obj->myDev->unlinkedDir); 2257 } else { 2258 unlinkOp = (newDir == obj->myDev->unlinkedDir 2259 && obj->variantType == YAFFS_OBJECT_TYPE_FILE); 2260 } 2261 2262 deleteOp = (newDir == obj->myDev->deletedDir); 2263 2264 existingTarget = yaffs_FindObjectByName(newDir, newName); 2265 2266 /* If the object is a file going into the unlinked directory, 2267 * then it is OK to just stuff it in since duplicate names are allowed. 2268 * else only proceed if the new name does not exist and if we're putting 2269 * it into a directory. 2270 */ 2271 if ((unlinkOp || 2272 deleteOp || 2273 force || 2274 (shadows > 0) || 2275 !existingTarget) && 2276 newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) { 2277 yaffs_SetObjectName(obj, newName); 2278 obj->dirty = 1; 2279 2280 yaffs_AddObjectToDirectory(newDir, obj); 2281 2282 if (unlinkOp) 2283 obj->unlinked = 1; 2284 2285 /* If it is a deletion then we mark it as a shrink for gc purposes. */ 2286 if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows)>= 0) 2287 return YAFFS_OK; 2288 } 2289 2290 return YAFFS_FAIL; 2291 } 2292 2293 int yaffs_RenameObject(yaffs_Object * oldDir, const YCHAR * oldName, 2294 yaffs_Object * newDir, const YCHAR * newName) 2295 { 2296 yaffs_Object *obj; 2297 yaffs_Object *existingTarget; 2298 int force = 0; 2299 2300 #ifdef CONFIG_YAFFS_CASE_INSENSITIVE 2301 /* Special case for case insemsitive systems (eg. WinCE). 2302 * While look-up is case insensitive, the name isn't. 2303 * Therefore we might want to change x.txt to X.txt 2304 */ 2305 if (oldDir == newDir && yaffs_strcmp(oldName, newName) == 0) { 2306 force = 1; 2307 } 2308 #endif 2309 2310 obj = yaffs_FindObjectByName(oldDir, oldName); 2311 /* Check new name to long. */ 2312 if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK && 2313 yaffs_strlen(newName) > YAFFS_MAX_ALIAS_LENGTH) 2314 /* ENAMETOOLONG */ 2315 return YAFFS_FAIL; 2316 else if (obj->variantType != YAFFS_OBJECT_TYPE_SYMLINK && 2317 yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH) 2318 /* ENAMETOOLONG */ 2319 return YAFFS_FAIL; 2320 2321 if (obj && obj->renameAllowed) { 2322 2323 /* Now do the handling for an existing target, if there is one */ 2324 2325 existingTarget = yaffs_FindObjectByName(newDir, newName); 2326 if (existingTarget && 2327 existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY && 2328 !list_empty(&existingTarget->variant.directoryVariant.children)) { 2329 /* There is a target that is a non-empty directory, so we fail */ 2330 return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */ 2331 } else if (existingTarget && existingTarget != obj) { 2332 /* Nuke the target first, using shadowing, 2333 * but only if it isn't the same object 2334 */ 2335 yaffs_ChangeObjectName(obj, newDir, newName, force, 2336 existingTarget->objectId); 2337 yaffs_UnlinkObject(existingTarget); 2338 } 2339 2340 return yaffs_ChangeObjectName(obj, newDir, newName, 1, 0); 2341 } 2342 return YAFFS_FAIL; 2343 } 2344 2345 /*------------------------- Block Management and Page Allocation ----------------*/ 2346 2347 static int yaffs_InitialiseBlocks(yaffs_Device * dev) 2348 { 2349 int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1; 2350 2351 dev->blockInfo = NULL; 2352 dev->chunkBits = NULL; 2353 2354 dev->allocationBlock = -1; /* force it to get a new one */ 2355 2356 /* If the first allocation strategy fails, thry the alternate one */ 2357 dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo)); 2358 if(!dev->blockInfo){ 2359 dev->blockInfo = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockInfo)); 2360 dev->blockInfoAlt = 1; 2361 } 2362 else 2363 dev->blockInfoAlt = 0; 2364 2365 if(dev->blockInfo){ 2366 2367 /* Set up dynamic blockinfo stuff. */ 2368 dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */ 2369 dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks); 2370 if(!dev->chunkBits){ 2371 dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks); 2372 dev->chunkBitsAlt = 1; 2373 } 2374 else 2375 dev->chunkBitsAlt = 0; 2376 } 2377 2378 if (dev->blockInfo && dev->chunkBits) { 2379 memset(dev->blockInfo, 0, nBlocks * sizeof(yaffs_BlockInfo)); 2380 memset(dev->chunkBits, 0, dev->chunkBitmapStride * nBlocks); 2381 return YAFFS_OK; 2382 } 2383 2384 return YAFFS_FAIL; 2385 2386 } 2387 2388 static void yaffs_DeinitialiseBlocks(yaffs_Device * dev) 2389 { 2390 if(dev->blockInfoAlt && dev->blockInfo) 2391 YFREE_ALT(dev->blockInfo); 2392 else if(dev->blockInfo) 2393 YFREE(dev->blockInfo); 2394 2395 dev->blockInfoAlt = 0; 2396 2397 dev->blockInfo = NULL; 2398 2399 if(dev->chunkBitsAlt && dev->chunkBits) 2400 YFREE_ALT(dev->chunkBits); 2401 else if(dev->chunkBits) 2402 YFREE(dev->chunkBits); 2403 dev->chunkBitsAlt = 0; 2404 dev->chunkBits = NULL; 2405 } 2406 2407 static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device * dev, 2408 yaffs_BlockInfo * bi) 2409 { 2410 int i; 2411 __u32 seq; 2412 yaffs_BlockInfo *b; 2413 2414 if (!dev->isYaffs2) 2415 return 1; /* disqualification only applies to yaffs2. */ 2416 2417 if (!bi->hasShrinkHeader) 2418 return 1; /* can gc */ 2419 2420 /* Find the oldest dirty sequence number if we don't know it and save it 2421 * so we don't have to keep recomputing it. 2422 */ 2423 if (!dev->oldestDirtySequence) { 2424 seq = dev->sequenceNumber; 2425 2426 for (i = dev->internalStartBlock; i <= dev->internalEndBlock; 2427 i++) { 2428 b = yaffs_GetBlockInfo(dev, i); 2429 if (b->blockState == YAFFS_BLOCK_STATE_FULL && 2430 (b->pagesInUse - b->softDeletions) < 2431 dev->nChunksPerBlock && b->sequenceNumber < seq) { 2432 seq = b->sequenceNumber; 2433 } 2434 } 2435 dev->oldestDirtySequence = seq; 2436 } 2437 2438 /* Can't do gc of this block if there are any blocks older than this one that have 2439 * discarded pages. 2440 */ 2441 return (bi->sequenceNumber <= dev->oldestDirtySequence); 2442 2443 } 2444 2445 /* FindDiretiestBlock is used to select the dirtiest block (or close enough) 2446 * for garbage collection. 2447 */ 2448 2449 static int yaffs_FindBlockForGarbageCollection(yaffs_Device * dev, 2450 int aggressive) 2451 { 2452 2453 int b = dev->currentDirtyChecker; 2454 2455 int i; 2456 int iterations; 2457 int dirtiest = -1; 2458 int pagesInUse = 0; 2459 int prioritised=0; 2460 yaffs_BlockInfo *bi; 2461 int pendingPrioritisedExist = 0; 2462 2463 /* First let's see if we need to grab a prioritised block */ 2464 if(dev->hasPendingPrioritisedGCs){ 2465 for(i = dev->internalStartBlock; i < dev->internalEndBlock && !prioritised; i++){ 2466 2467 bi = yaffs_GetBlockInfo(dev, i); 2468 //yaffs_VerifyBlock(dev,bi,i); 2469 2470 if(bi->gcPrioritise) { 2471 pendingPrioritisedExist = 1; 2472 if(bi->blockState == YAFFS_BLOCK_STATE_FULL && 2473 yaffs_BlockNotDisqualifiedFromGC(dev, bi)){ 2474 pagesInUse = (bi->pagesInUse - bi->softDeletions); 2475 dirtiest = i; 2476 prioritised = 1; 2477 aggressive = 1; /* Fool the non-aggressive skip logiv below */ 2478 } 2479 } 2480 } 2481 2482 if(!pendingPrioritisedExist) /* None found, so we can clear this */ 2483 dev->hasPendingPrioritisedGCs = 0; 2484 } 2485 2486 /* If we're doing aggressive GC then we are happy to take a less-dirty block, and 2487 * search harder. 2488 * else (we're doing a leasurely gc), then we only bother to do this if the 2489 * block has only a few pages in use. 2490 */ 2491 2492 dev->nonAggressiveSkip--; 2493 2494 if (!aggressive && (dev->nonAggressiveSkip > 0)) { 2495 return -1; 2496 } 2497 2498 if(!prioritised) 2499 pagesInUse = 2500 (aggressive) ? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1; 2501 2502 if (aggressive) { 2503 iterations = 2504 dev->internalEndBlock - dev->internalStartBlock + 1; 2505 } else { 2506 iterations = 2507 dev->internalEndBlock - dev->internalStartBlock + 1; 2508 iterations = iterations / 16; 2509 if (iterations > 200) { 2510 iterations = 200; 2511 } 2512 } 2513 2514 for (i = 0; i <= iterations && pagesInUse > 0 && !prioritised; i++) { 2515 b++; 2516 if (b < dev->internalStartBlock || b > dev->internalEndBlock) { 2517 b = dev->internalStartBlock; 2518 } 2519 2520 if (b < dev->internalStartBlock || b > dev->internalEndBlock) { 2521 T(YAFFS_TRACE_ERROR, 2522 (TSTR("**>> Block %d is not valid" TENDSTR), b)); 2523 YBUG(); 2524 } 2525 2526 bi = yaffs_GetBlockInfo(dev, b); 2527 2528 #if 0 2529 if (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT) { 2530 dirtiest = b; 2531 pagesInUse = 0; 2532 } 2533 else 2534 #endif 2535 2536 if (bi->blockState == YAFFS_BLOCK_STATE_FULL && 2537 (bi->pagesInUse - bi->softDeletions) < pagesInUse && 2538 yaffs_BlockNotDisqualifiedFromGC(dev, bi)) { 2539 dirtiest = b; 2540 pagesInUse = (bi->pagesInUse - bi->softDeletions); 2541 } 2542 } 2543 2544 dev->currentDirtyChecker = b; 2545 2546 if (dirtiest > 0) { 2547 T(YAFFS_TRACE_GC, 2548 (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR), dirtiest, 2549 dev->nChunksPerBlock - pagesInUse,prioritised)); 2550 } 2551 2552 dev->oldestDirtySequence = 0; 2553 2554 if (dirtiest > 0) { 2555 dev->nonAggressiveSkip = 4; 2556 } 2557 2558 return dirtiest; 2559 } 2560 2561 static void yaffs_BlockBecameDirty(yaffs_Device * dev, int blockNo) 2562 { 2563 yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockNo); 2564 2565 int erasedOk = 0; 2566 2567 /* If the block is still healthy erase it and mark as clean. 2568 * If the block has had a data failure, then retire it. 2569 */ 2570 2571 T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE, 2572 (TSTR("yaffs_BlockBecameDirty block %d state %d %s"TENDSTR), 2573 blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : "")); 2574 2575 bi->blockState = YAFFS_BLOCK_STATE_DIRTY; 2576 2577 if (!bi->needsRetiring) { 2578 yaffs_InvalidateCheckpoint(dev); 2579 erasedOk = yaffs_EraseBlockInNAND(dev, blockNo); 2580 if (!erasedOk) { 2581 dev->nErasureFailures++; 2582 T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, 2583 (TSTR("**>> Erasure failed %d" TENDSTR), blockNo)); 2584 } 2585 } 2586 2587 if (erasedOk && 2588 ((yaffs_traceMask & YAFFS_TRACE_ERASE) || !yaffs_SkipVerification(dev))) { 2589 int i; 2590 for (i = 0; i < dev->nChunksPerBlock; i++) { 2591 if (!yaffs_CheckChunkErased 2592 (dev, blockNo * dev->nChunksPerBlock + i)) { 2593 T(YAFFS_TRACE_ERROR, 2594 (TSTR 2595 (">>Block %d erasure supposedly OK, but chunk %d not erased" 2596 TENDSTR), blockNo, i)); 2597 } 2598 } 2599 } 2600 2601 if (erasedOk) { 2602 /* Clean it up... */ 2603 bi->blockState = YAFFS_BLOCK_STATE_EMPTY; 2604 dev->nErasedBlocks++; 2605 bi->pagesInUse = 0; 2606 bi->softDeletions = 0; 2607 bi->hasShrinkHeader = 0; 2608 bi->skipErasedCheck = 1; /* This is clean, so no need to check */ 2609 bi->gcPrioritise = 0; 2610 yaffs_ClearChunkBits(dev, blockNo); 2611 2612 T(YAFFS_TRACE_ERASE, 2613 (TSTR("Erased block %d" TENDSTR), blockNo)); 2614 } else { 2615 dev->nFreeChunks -= dev->nChunksPerBlock; /* We lost a block of free space */ 2616 2617 yaffs_RetireBlock(dev, blockNo); 2618 T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, 2619 (TSTR("**>> Block %d retired" TENDSTR), blockNo)); 2620 } 2621 } 2622 2623 static int yaffs_FindBlockForAllocation(yaffs_Device * dev) 2624 { 2625 int i; 2626 2627 yaffs_BlockInfo *bi; 2628 2629 if (dev->nErasedBlocks < 1) { 2630 /* Hoosterman we've got a problem. 2631 * Can't get space to gc 2632 */ 2633 T(YAFFS_TRACE_ERROR, 2634 (TSTR("yaffs tragedy: no more eraased blocks" TENDSTR))); 2635 2636 return -1; 2637 } 2638 2639 /* Find an empty block. */ 2640 2641 for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { 2642 dev->allocationBlockFinder++; 2643 if (dev->allocationBlockFinder < dev->internalStartBlock 2644 || dev->allocationBlockFinder > dev->internalEndBlock) { 2645 dev->allocationBlockFinder = dev->internalStartBlock; 2646 } 2647 2648 bi = yaffs_GetBlockInfo(dev, dev->allocationBlockFinder); 2649 2650 if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) { 2651 bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING; 2652 dev->sequenceNumber++; 2653 bi->sequenceNumber = dev->sequenceNumber; 2654 dev->nErasedBlocks--; 2655 T(YAFFS_TRACE_ALLOCATE, 2656 (TSTR("Allocated block %d, seq %d, %d left" TENDSTR), 2657 dev->allocationBlockFinder, dev->sequenceNumber, 2658 dev->nErasedBlocks)); 2659 return dev->allocationBlockFinder; 2660 } 2661 } 2662 2663 T(YAFFS_TRACE_ALWAYS, 2664 (TSTR 2665 ("yaffs tragedy: no more eraased blocks, but there should have been %d" 2666 TENDSTR), dev->nErasedBlocks)); 2667 2668 return -1; 2669 } 2670 2671 2672 // Check if there's space to allocate... 2673 // Thinks.... do we need top make this ths same as yaffs_GetFreeChunks()? 2674 static int yaffs_CheckSpaceForAllocation(yaffs_Device * dev) 2675 { 2676 int reservedChunks; 2677 int reservedBlocks = dev->nReservedBlocks; 2678 int checkpointBlocks; 2679 2680 checkpointBlocks = dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint; 2681 if(checkpointBlocks < 0) 2682 checkpointBlocks = 0; 2683 2684 reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->nChunksPerBlock); 2685 2686 return (dev->nFreeChunks > reservedChunks); 2687 } 2688 2689 static int yaffs_AllocateChunk(yaffs_Device * dev, int useReserve, yaffs_BlockInfo **blockUsedPtr) 2690 { 2691 int retVal; 2692 yaffs_BlockInfo *bi; 2693 2694 if (dev->allocationBlock < 0) { 2695 /* Get next block to allocate off */ 2696 dev->allocationBlock = yaffs_FindBlockForAllocation(dev); 2697 dev->allocationPage = 0; 2698 } 2699 2700 if (!useReserve && !yaffs_CheckSpaceForAllocation(dev)) { 2701 /* Not enough space to allocate unless we're allowed to use the reserve. */ 2702 return -1; 2703 } 2704 2705 if (dev->nErasedBlocks < dev->nReservedBlocks 2706 && dev->allocationPage == 0) { 2707 T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR))); 2708 } 2709 2710 /* Next page please.... */ 2711 if (dev->allocationBlock >= 0) { 2712 bi = yaffs_GetBlockInfo(dev, dev->allocationBlock); 2713 2714 retVal = (dev->allocationBlock * dev->nChunksPerBlock) + 2715 dev->allocationPage; 2716 bi->pagesInUse++; 2717 yaffs_SetChunkBit(dev, dev->allocationBlock, 2718 dev->allocationPage); 2719 2720 dev->allocationPage++; 2721 2722 dev->nFreeChunks--; 2723 2724 /* If the block is full set the state to full */ 2725 if (dev->allocationPage >= dev->nChunksPerBlock) { 2726 bi->blockState = YAFFS_BLOCK_STATE_FULL; 2727 dev->allocationBlock = -1; 2728 } 2729 2730 if(blockUsedPtr) 2731 *blockUsedPtr = bi; 2732 2733 return retVal; 2734 } 2735 2736 T(YAFFS_TRACE_ERROR, 2737 (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR))); 2738 2739 return -1; 2740 } 2741 2742 static int yaffs_GetErasedChunks(yaffs_Device * dev) 2743 { 2744 int n; 2745 2746 n = dev->nErasedBlocks * dev->nChunksPerBlock; 2747 2748 if (dev->allocationBlock > 0) { 2749 n += (dev->nChunksPerBlock - dev->allocationPage); 2750 } 2751 2752 return n; 2753 2754 } 2755 2756 static int yaffs_GarbageCollectBlock(yaffs_Device * dev, int block) 2757 { 2758 int oldChunk; 2759 int newChunk; 2760 int chunkInBlock; 2761 int markNAND; 2762 int retVal = YAFFS_OK; 2763 int cleanups = 0; 2764 int i; 2765 int isCheckpointBlock; 2766 int matchingChunk; 2767 2768 int chunksBefore = yaffs_GetErasedChunks(dev); 2769 int chunksAfter; 2770 2771 yaffs_ExtendedTags tags; 2772 2773 yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, block); 2774 2775 yaffs_Object *object; 2776 2777 isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT); 2778 2779 bi->blockState = YAFFS_BLOCK_STATE_COLLECTING; 2780 2781 T(YAFFS_TRACE_TRACING, 2782 (TSTR("Collecting block %d, in use %d, shrink %d, " TENDSTR), block, 2783 bi->pagesInUse, bi->hasShrinkHeader)); 2784 2785 /*yaffs_VerifyFreeChunks(dev); */ 2786 2787 bi->hasShrinkHeader = 0; /* clear the flag so that the block can erase */ 2788 2789 /* Take off the number of soft deleted entries because 2790 * they're going to get really deleted during GC. 2791 */ 2792 dev->nFreeChunks -= bi->softDeletions; 2793 2794 dev->isDoingGC = 1; 2795 2796 if (isCheckpointBlock || 2797 !yaffs_StillSomeChunkBits(dev, block)) { 2798 T(YAFFS_TRACE_TRACING, 2799 (TSTR 2800 ("Collecting block %d that has no chunks in use" TENDSTR), 2801 block)); 2802 yaffs_BlockBecameDirty(dev, block); 2803 } else { 2804 2805 __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__); 2806 2807 yaffs_VerifyBlock(dev,bi,block); 2808 2809 for (chunkInBlock = 0, oldChunk = block * dev->nChunksPerBlock; 2810 chunkInBlock < dev->nChunksPerBlock 2811 && yaffs_StillSomeChunkBits(dev, block); 2812 chunkInBlock++, oldChunk++) { 2813 if (yaffs_CheckChunkBit(dev, block, chunkInBlock)) { 2814 2815 /* This page is in use and might need to be copied off */ 2816 2817 markNAND = 1; 2818 2819 yaffs_InitialiseTags(&tags); 2820 2821 yaffs_ReadChunkWithTagsFromNAND(dev, oldChunk, 2822 buffer, &tags); 2823 2824 object = 2825 yaffs_FindObjectByNumber(dev, 2826 tags.objectId); 2827 2828 T(YAFFS_TRACE_GC_DETAIL, 2829 (TSTR 2830 ("Collecting page %d, %d %d %d " TENDSTR), 2831 chunkInBlock, tags.objectId, tags.chunkId, 2832 tags.byteCount)); 2833 2834 if(object && !yaffs_SkipVerification(dev)){ 2835 if(tags.chunkId == 0) 2836 matchingChunk = object->chunkId; 2837 else if(object->softDeleted) 2838 matchingChunk = oldChunk; /* Defeat the test */ 2839 else 2840 matchingChunk = yaffs_FindChunkInFile(object,tags.chunkId,NULL); 2841 2842 if(oldChunk != matchingChunk) 2843 T(YAFFS_TRACE_ERROR, 2844 (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR), 2845 oldChunk,matchingChunk,tags.objectId, tags.chunkId)); 2846 2847 } 2848 2849 if (!object) { 2850 T(YAFFS_TRACE_ERROR, 2851 (TSTR 2852 ("page %d in gc has no object: %d %d %d " 2853 TENDSTR), oldChunk, 2854 tags.objectId, tags.chunkId, tags.byteCount)); 2855 } 2856 2857 if (object && object->deleted 2858 && tags.chunkId != 0) { 2859 /* Data chunk in a deleted file, throw it away 2860 * It's a soft deleted data chunk, 2861 * No need to copy this, just forget about it and 2862 * fix up the object. 2863 */ 2864 2865 object->nDataChunks--; 2866 2867 if (object->nDataChunks <= 0) { 2868 /* remeber to clean up the object */ 2869 dev->gcCleanupList[cleanups] = 2870 tags.objectId; 2871 cleanups++; 2872 } 2873 markNAND = 0; 2874 } else if (0 2875 /* Todo object && object->deleted && object->nDataChunks == 0 */ 2876 ) { 2877 /* Deleted object header with no data chunks. 2878 * Can be discarded and the file deleted. 2879 */ 2880 object->chunkId = 0; 2881 yaffs_FreeTnode(object->myDev, 2882 object->variant. 2883 fileVariant.top); 2884 object->variant.fileVariant.top = NULL; 2885 yaffs_DoGenericObjectDeletion(object); 2886 2887 } else if (object) { 2888 /* It's either a data chunk in a live file or 2889 * an ObjectHeader, so we're interested in it. 2890 * NB Need to keep the ObjectHeaders of deleted files 2891 * until the whole file has been deleted off 2892 */ 2893 tags.serialNumber++; 2894 2895 dev->nGCCopies++; 2896 2897 if (tags.chunkId == 0) { 2898 /* It is an object Id, 2899 * We need to nuke the shrinkheader flags first 2900 * We no longer want the shrinkHeader flag since its work is done 2901 * and if it is left in place it will mess up scanning. 2902 * Also, clear out any shadowing stuff 2903 */ 2904 2905 yaffs_ObjectHeader *oh; 2906 oh = (yaffs_ObjectHeader *)buffer; 2907 oh->isShrink = 0; 2908 oh->shadowsObject = -1; 2909 tags.extraShadows = 0; 2910 tags.extraIsShrinkHeader = 0; 2911 2912 yaffs_VerifyObjectHeader(object,oh,&tags,1); 2913 } 2914 2915 newChunk = 2916 yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags, 1); 2917 2918 if (newChunk < 0) { 2919 retVal = YAFFS_FAIL; 2920 } else { 2921 2922 /* Ok, now fix up the Tnodes etc. */ 2923 2924 if (tags.chunkId == 0) { 2925 /* It's a header */ 2926 object->chunkId = newChunk; 2927 object->serial = tags.serialNumber; 2928 } else { 2929 /* It's a data chunk */ 2930 yaffs_PutChunkIntoFile 2931 (object, 2932 tags.chunkId, 2933 newChunk, 0); 2934 } 2935 } 2936 } 2937 2938 yaffs_DeleteChunk(dev, oldChunk, markNAND, __LINE__); 2939 2940 } 2941 } 2942 2943 yaffs_ReleaseTempBuffer(dev, buffer, __LINE__); 2944 2945 2946 /* Do any required cleanups */ 2947 for (i = 0; i < cleanups; i++) { 2948 /* Time to delete the file too */ 2949 object = 2950 yaffs_FindObjectByNumber(dev, 2951 dev->gcCleanupList[i]); 2952 if (object) { 2953 yaffs_FreeTnode(dev, 2954 object->variant.fileVariant. 2955 top); 2956 object->variant.fileVariant.top = NULL; 2957 T(YAFFS_TRACE_GC, 2958 (TSTR 2959 ("yaffs: About to finally delete object %d" 2960 TENDSTR), object->objectId)); 2961 yaffs_DoGenericObjectDeletion(object); 2962 object->myDev->nDeletedFiles--; 2963 } 2964 2965 } 2966 2967 } 2968 2969 yaffs_VerifyCollectedBlock(dev,bi,block); 2970 2971 if (chunksBefore >= (chunksAfter = yaffs_GetErasedChunks(dev))) { 2972 T(YAFFS_TRACE_GC, 2973 (TSTR 2974 ("gc did not increase free chunks before %d after %d" 2975 TENDSTR), chunksBefore, chunksAfter)); 2976 } 2977 2978 dev->isDoingGC = 0; 2979 2980 return YAFFS_OK; 2981 } 2982 2983 /* New garbage collector 2984 * If we're very low on erased blocks then we do aggressive garbage collection 2985 * otherwise we do "leasurely" garbage collection. 2986 * Aggressive gc looks further (whole array) and will accept less dirty blocks. 2987 * Passive gc only inspects smaller areas and will only accept more dirty blocks. 2988 * 2989 * The idea is to help clear out space in a more spread-out manner. 2990 * Dunno if it really does anything useful. 2991 */ 2992 static int yaffs_CheckGarbageCollection(yaffs_Device * dev) 2993 { 2994 int block; 2995 int aggressive; 2996 int gcOk = YAFFS_OK; 2997 int maxTries = 0; 2998 2999 int checkpointBlockAdjust; 3000 3001 if (dev->isDoingGC) { 3002 /* Bail out so we don't get recursive gc */ 3003 return YAFFS_OK; 3004 } 3005 3006 /* This loop should pass the first time. 3007 * We'll only see looping here if the erase of the collected block fails. 3008 */ 3009 3010 do { 3011 maxTries++; 3012 3013 checkpointBlockAdjust = (dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint); 3014 if(checkpointBlockAdjust < 0) 3015 checkpointBlockAdjust = 0; 3016 3017 if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust + 2)) { 3018 /* We need a block soon...*/ 3019 aggressive = 1; 3020 } else { 3021 /* We're in no hurry */ 3022 aggressive = 0; 3023 } 3024 3025 block = yaffs_FindBlockForGarbageCollection(dev, aggressive); 3026 3027 if (block > 0) { 3028 dev->garbageCollections++; 3029 if (!aggressive) { 3030 dev->passiveGarbageCollections++; 3031 } 3032 3033 T(YAFFS_TRACE_GC, 3034 (TSTR 3035 ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR), 3036 dev->nErasedBlocks, aggressive)); 3037 3038 gcOk = yaffs_GarbageCollectBlock(dev, block); 3039 } 3040 3041 if (dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0) { 3042 T(YAFFS_TRACE_GC, 3043 (TSTR 3044 ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d" 3045 TENDSTR), dev->nErasedBlocks, maxTries, block)); 3046 } 3047 } while ((dev->nErasedBlocks < dev->nReservedBlocks) && (block > 0) 3048 && (maxTries < 2)); 3049 3050 return aggressive ? gcOk : YAFFS_OK; 3051 } 3052 3053 /*------------------------- TAGS --------------------------------*/ 3054 3055 static int yaffs_TagsMatch(const yaffs_ExtendedTags * tags, int objectId, 3056 int chunkInObject) 3057 { 3058 return (tags->chunkId == chunkInObject && 3059 tags->objectId == objectId && !tags->chunkDeleted) ? 1 : 0; 3060 3061 } 3062 3063 3064 /*-------------------- Data file manipulation -----------------*/ 3065 3066 static int yaffs_FindChunkInFile(yaffs_Object * in, int chunkInInode, 3067 yaffs_ExtendedTags * tags) 3068 { 3069 /*Get the Tnode, then get the level 0 offset chunk offset */ 3070 yaffs_Tnode *tn; 3071 int theChunk = -1; 3072 yaffs_ExtendedTags localTags; 3073 int retVal = -1; 3074 3075 yaffs_Device *dev = in->myDev; 3076 3077 if (!tags) { 3078 /* Passed a NULL, so use our own tags space */ 3079 tags = &localTags; 3080 } 3081 3082 tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode); 3083 3084 if (tn) { 3085 theChunk = yaffs_GetChunkGroupBase(dev,tn,chunkInInode); 3086 3087 retVal = 3088 yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId, 3089 chunkInInode); 3090 } 3091 return retVal; 3092 } 3093 3094 static int yaffs_FindAndDeleteChunkInFile(yaffs_Object * in, int chunkInInode, 3095 yaffs_ExtendedTags * tags) 3096 { 3097 /* Get the Tnode, then get the level 0 offset chunk offset */ 3098 yaffs_Tnode *tn; 3099 int theChunk = -1; 3100 yaffs_ExtendedTags localTags; 3101 3102 yaffs_Device *dev = in->myDev; 3103 int retVal = -1; 3104 3105 if (!tags) { 3106 /* Passed a NULL, so use our own tags space */ 3107 tags = &localTags; 3108 } 3109 3110 tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode); 3111 3112 if (tn) { 3113 3114 theChunk = yaffs_GetChunkGroupBase(dev,tn,chunkInInode); 3115 3116 retVal = 3117 yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId, 3118 chunkInInode); 3119 3120 /* Delete the entry in the filestructure (if found) */ 3121 if (retVal != -1) { 3122 yaffs_PutLevel0Tnode(dev,tn,chunkInInode,0); 3123 } 3124 } else { 3125 /*T(("No level 0 found for %d\n", chunkInInode)); */ 3126 } 3127 3128 if (retVal == -1) { 3129 /* T(("Could not find %d to delete\n",chunkInInode)); */ 3130 } 3131 return retVal; 3132 } 3133 3134 #ifdef YAFFS_PARANOID 3135 3136 static int yaffs_CheckFileSanity(yaffs_Object * in) 3137 { 3138 int chunk; 3139 int nChunks; 3140 int fSize; 3141 int failed = 0; 3142 int objId; 3143 yaffs_Tnode *tn; 3144 yaffs_Tags localTags; 3145 yaffs_Tags *tags = &localTags; 3146 int theChunk; 3147 int chunkDeleted; 3148 3149 if (in->variantType != YAFFS_OBJECT_TYPE_FILE) { 3150 /* T(("Object not a file\n")); */ 3151 return YAFFS_FAIL; 3152 } 3153 3154 objId = in->objectId; 3155 fSize = in->variant.fileVariant.fileSize; 3156 nChunks = 3157 (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk; 3158 3159 for (chunk = 1; chunk <= nChunks; chunk++) { 3160 tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant, 3161 chunk); 3162 3163 if (tn) { 3164 3165 theChunk = yaffs_GetChunkGroupBase(dev,tn,chunk); 3166 3167 if (yaffs_CheckChunkBits 3168 (dev, theChunk / dev->nChunksPerBlock, 3169 theChunk % dev->nChunksPerBlock)) { 3170 3171 yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk, 3172 tags, 3173 &chunkDeleted); 3174 if (yaffs_TagsMatch 3175 (tags, in->objectId, chunk, chunkDeleted)) { 3176 /* found it; */ 3177 3178 } 3179 } else { 3180 3181 failed = 1; 3182 } 3183 3184 } else { 3185 /* T(("No level 0 found for %d\n", chunk)); */ 3186 } 3187 } 3188 3189 return failed ? YAFFS_FAIL : YAFFS_OK; 3190 } 3191 3192 #endif 3193 3194 static int yaffs_PutChunkIntoFile(yaffs_Object * in, int chunkInInode, 3195 int chunkInNAND, int inScan) 3196 { 3197 /* NB inScan is zero unless scanning. 3198 * For forward scanning, inScan is > 0; 3199 * for backward scanning inScan is < 0 3200 */ 3201 3202 yaffs_Tnode *tn; 3203 yaffs_Device *dev = in->myDev; 3204 int existingChunk; 3205 yaffs_ExtendedTags existingTags; 3206 yaffs_ExtendedTags newTags; 3207 unsigned existingSerial, newSerial; 3208 3209 if (in->variantType != YAFFS_OBJECT_TYPE_FILE) { 3210 /* Just ignore an attempt at putting a chunk into a non-file during scanning 3211 * If it is not during Scanning then something went wrong! 3212 */ 3213 if (!inScan) { 3214 T(YAFFS_TRACE_ERROR, 3215 (TSTR 3216 ("yaffs tragedy:attempt to put data chunk into a non-file" 3217 TENDSTR))); 3218 YBUG(); 3219 } 3220 3221 yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__); 3222 return YAFFS_OK; 3223 } 3224 3225 tn = yaffs_AddOrFindLevel0Tnode(dev, 3226 &in->variant.fileVariant, 3227 chunkInInode, 3228 NULL); 3229 if (!tn) { 3230 return YAFFS_FAIL; 3231 } 3232 3233 existingChunk = yaffs_GetChunkGroupBase(dev,tn,chunkInInode); 3234 3235 if (inScan != 0) { 3236 /* If we're scanning then we need to test for duplicates 3237 * NB This does not need to be efficient since it should only ever 3238 * happen when the power fails during a write, then only one 3239 * chunk should ever be affected. 3240 * 3241 * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO 3242 * Update: For backward scanning we don't need to re-read tags so this is quite cheap. 3243 */ 3244 3245 if (existingChunk != 0) { 3246 /* NB Right now existing chunk will not be real chunkId if the device >= 32MB 3247 * thus we have to do a FindChunkInFile to get the real chunk id. 3248 * 3249 * We have a duplicate now we need to decide which one to use: 3250 * 3251 * Backwards scanning YAFFS2: The old one is what we use, dump the new one. 3252 * Forward scanning YAFFS2: The new one is what we use, dump the old one. 3253 * YAFFS1: Get both sets of tags and compare serial numbers. 3254 */ 3255 3256 if (inScan > 0) { 3257 /* Only do this for forward scanning */ 3258 yaffs_ReadChunkWithTagsFromNAND(dev, 3259 chunkInNAND, 3260 NULL, &newTags); 3261 3262 /* Do a proper find */ 3263 existingChunk = 3264 yaffs_FindChunkInFile(in, chunkInInode, 3265 &existingTags); 3266 } 3267 3268 if (existingChunk <= 0) { 3269 /*Hoosterman - how did this happen? */ 3270 3271 T(YAFFS_TRACE_ERROR, 3272 (TSTR 3273 ("yaffs tragedy: existing chunk < 0 in scan" 3274 TENDSTR))); 3275 3276 } 3277 3278 /* NB The deleted flags should be false, otherwise the chunks will 3279 * not be loaded during a scan 3280 */ 3281 3282 newSerial = newTags.serialNumber; 3283 existingSerial = existingTags.serialNumber; 3284 3285 if ((inScan > 0) && 3286 (in->myDev->isYaffs2 || 3287 existingChunk <= 0 || 3288 ((existingSerial + 1) & 3) == newSerial)) { 3289 /* Forward scanning. 3290 * Use new 3291 * Delete the old one and drop through to update the tnode 3292 */ 3293 yaffs_DeleteChunk(dev, existingChunk, 1, 3294 __LINE__); 3295 } else { 3296 /* Backward scanning or we want to use the existing one 3297 * Use existing. 3298 * Delete the new one and return early so that the tnode isn't changed 3299 */ 3300 yaffs_DeleteChunk(dev, chunkInNAND, 1, 3301 __LINE__); 3302 return YAFFS_OK; 3303 } 3304 } 3305 3306 } 3307 3308 if (existingChunk == 0) { 3309 in->nDataChunks++; 3310 } 3311 3312 yaffs_PutLevel0Tnode(dev,tn,chunkInInode,chunkInNAND); 3313 3314 return YAFFS_OK; 3315 } 3316 3317 static int yaffs_ReadChunkDataFromObject(yaffs_Object * in, int chunkInInode, 3318 __u8 * buffer) 3319 { 3320 int chunkInNAND = yaffs_FindChunkInFile(in, chunkInInode, NULL); 3321 3322 if (chunkInNAND >= 0) { 3323 return yaffs_ReadChunkWithTagsFromNAND(in->myDev, chunkInNAND, 3324 buffer,NULL); 3325 } else { 3326 T(YAFFS_TRACE_NANDACCESS, 3327 (TSTR("Chunk %d not found zero instead" TENDSTR), 3328 chunkInNAND)); 3329 /* get sane (zero) data if you read a hole */ 3330 memset(buffer, 0, in->myDev->nDataBytesPerChunk); 3331 return 0; 3332 } 3333 3334 } 3335 3336 void yaffs_DeleteChunk(yaffs_Device * dev, int chunkId, int markNAND, int lyn) 3337 { 3338 int block; 3339 int page; 3340 yaffs_ExtendedTags tags; 3341 yaffs_BlockInfo *bi; 3342 3343 if (chunkId <= 0) 3344 return; 3345 3346 3347 dev->nDeletions++; 3348 block = chunkId / dev->nChunksPerBlock; 3349 page = chunkId % dev->nChunksPerBlock; 3350 3351 3352 if(!yaffs_CheckChunkBit(dev,block,page)) 3353 T(YAFFS_TRACE_VERIFY, 3354 (TSTR("Deleting invalid chunk %d"TENDSTR), 3355 chunkId)); 3356 3357 bi = yaffs_GetBlockInfo(dev, block); 3358 3359 T(YAFFS_TRACE_DELETION, 3360 (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunkId)); 3361 3362 if (markNAND && 3363 bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && !dev->isYaffs2) { 3364 3365 yaffs_InitialiseTags(&tags); 3366 3367 tags.chunkDeleted = 1; 3368 3369 yaffs_WriteChunkWithTagsToNAND(dev, chunkId, NULL, &tags); 3370 yaffs_HandleUpdateChunk(dev, chunkId, &tags); 3371 } else { 3372 dev->nUnmarkedDeletions++; 3373 } 3374 3375 /* Pull out of the management area. 3376 * If the whole block became dirty, this will kick off an erasure. 3377 */ 3378 if (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || 3379 bi->blockState == YAFFS_BLOCK_STATE_FULL || 3380 bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING || 3381 bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) { 3382 dev->nFreeChunks++; 3383 3384 yaffs_ClearChunkBit(dev, block, page); 3385 3386 bi->pagesInUse--; 3387 3388 if (bi->pagesInUse == 0 && 3389 !bi->hasShrinkHeader && 3390 bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING && 3391 bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING) { 3392 yaffs_BlockBecameDirty(dev, block); 3393 } 3394 3395 } else { 3396 /* T(("Bad news deleting chunk %d\n",chunkId)); */ 3397 } 3398 3399 } 3400 3401 static int yaffs_WriteChunkDataToObject(yaffs_Object * in, int chunkInInode, 3402 const __u8 * buffer, int nBytes, 3403 int useReserve) 3404 { 3405 /* Find old chunk Need to do this to get serial number 3406 * Write new one and patch into tree. 3407 * Invalidate old tags. 3408 */ 3409 3410 int prevChunkId; 3411 yaffs_ExtendedTags prevTags; 3412 3413 int newChunkId; 3414 yaffs_ExtendedTags newTags; 3415 3416 yaffs_Device *dev = in->myDev; 3417 3418 yaffs_CheckGarbageCollection(dev); 3419 3420 /* Get the previous chunk at this location in the file if it exists */ 3421 prevChunkId = yaffs_FindChunkInFile(in, chunkInInode, &prevTags); 3422 3423 /* Set up new tags */ 3424 yaffs_InitialiseTags(&newTags); 3425 3426 newTags.chunkId = chunkInInode; 3427 newTags.objectId = in->objectId; 3428 newTags.serialNumber = 3429 (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1; 3430 newTags.byteCount = nBytes; 3431 3432 newChunkId = 3433 yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags, 3434 useReserve); 3435 3436 if (newChunkId >= 0) { 3437 yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0); 3438 3439 if (prevChunkId >= 0) { 3440 yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__); 3441 3442 } 3443 3444 yaffs_CheckFileSanity(in); 3445 } 3446 return newChunkId; 3447 3448 } 3449 3450 /* UpdateObjectHeader updates the header on NAND for an object. 3451 * If name is not NULL, then that new name is used. 3452 */ 3453 int yaffs_UpdateObjectHeader(yaffs_Object * in, const YCHAR * name, int force, 3454 int isShrink, int shadows) 3455 { 3456 3457 yaffs_BlockInfo *bi; 3458 3459 yaffs_Device *dev = in->myDev; 3460 3461 int prevChunkId; 3462 int retVal = 0; 3463 int result = 0; 3464 3465 int newChunkId; 3466 yaffs_ExtendedTags newTags; 3467 yaffs_ExtendedTags oldTags; 3468 3469 __u8 *buffer = NULL; 3470 YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1]; 3471 3472 yaffs_ObjectHeader *oh = NULL; 3473 3474 yaffs_strcpy(oldName,"silly old name"); 3475 3476 if (!in->fake || force) { 3477 3478 yaffs_CheckGarbageCollection(dev); 3479 yaffs_CheckObjectDetailsLoaded(in); 3480 3481 buffer = yaffs_GetTempBuffer(in->myDev, __LINE__); 3482 oh = (yaffs_ObjectHeader *) buffer; 3483 3484 prevChunkId = in->chunkId; 3485 3486 if (prevChunkId >= 0) { 3487 result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId, 3488 buffer, &oldTags); 3489 3490 yaffs_VerifyObjectHeader(in,oh,&oldTags,0); 3491 3492 memcpy(oldName, oh->name, sizeof(oh->name)); 3493 } 3494 3495 memset(buffer, 0xFF, dev->nDataBytesPerChunk); 3496 3497 oh->type = in->variantType; 3498 oh->yst_mode = in->yst_mode; 3499 oh->shadowsObject = shadows; 3500 3501 #ifdef CONFIG_YAFFS_WINCE 3502 oh->win_atime[0] = in->win_atime[0]; 3503 oh->win_ctime[0] = in->win_ctime[0]; 3504 oh->win_mtime[0] = in->win_mtime[0]; 3505 oh->win_atime[1] = in->win_atime[1]; 3506 oh->win_ctime[1] = in->win_ctime[1]; 3507 oh->win_mtime[1] = in->win_mtime[1]; 3508 #else 3509 oh->yst_uid = in->yst_uid; 3510 oh->yst_gid = in->yst_gid; 3511 oh->yst_atime = in->yst_atime; 3512 oh->yst_mtime = in->yst_mtime; 3513 oh->yst_ctime = in->yst_ctime; 3514 oh->yst_rdev = in->yst_rdev; 3515 #endif 3516 if (in->parent) { 3517 oh->parentObjectId = in->parent->objectId; 3518 } else { 3519 oh->parentObjectId = 0; 3520 } 3521 3522 if (name && *name) { 3523 memset(oh->name, 0, sizeof(oh->name)); 3524 yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH); 3525 } else if (prevChunkId>=0) { 3526 memcpy(oh->name, oldName, sizeof(oh->name)); 3527 } else { 3528 memset(oh->name, 0, sizeof(oh->name)); 3529 } 3530 3531 oh->isShrink = isShrink; 3532 3533 switch (in->variantType) { 3534 case YAFFS_OBJECT_TYPE_UNKNOWN: 3535 /* Should not happen */ 3536 break; 3537 case YAFFS_OBJECT_TYPE_FILE: 3538 oh->fileSize = 3539 (oh->parentObjectId == YAFFS_OBJECTID_DELETED 3540 || oh->parentObjectId == 3541 YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant. 3542 fileVariant.fileSize; 3543 break; 3544 case YAFFS_OBJECT_TYPE_HARDLINK: 3545 oh->equivalentObjectId = 3546 in->variant.hardLinkVariant.equivalentObjectId; 3547 break; 3548 case YAFFS_OBJECT_TYPE_SPECIAL: 3549 /* Do nothing */ 3550 break; 3551 case YAFFS_OBJECT_TYPE_DIRECTORY: 3552 /* Do nothing */ 3553 break; 3554 case YAFFS_OBJECT_TYPE_SYMLINK: 3555 yaffs_strncpy(oh->alias, 3556 in->variant.symLinkVariant.alias, 3557 YAFFS_MAX_ALIAS_LENGTH); 3558 oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0; 3559 break; 3560 } 3561 3562 /* Tags */ 3563 yaffs_InitialiseTags(&newTags); 3564 in->serial++; 3565 newTags.chunkId = 0; 3566 newTags.objectId = in->objectId; 3567 newTags.serialNumber = in->serial; 3568 3569 /* Add extra info for file header */ 3570 3571 newTags.extraHeaderInfoAvailable = 1; 3572 newTags.extraParentObjectId = oh->parentObjectId; 3573 newTags.extraFileLength = oh->fileSize; 3574 newTags.extraIsShrinkHeader = oh->isShrink; 3575 newTags.extraEquivalentObjectId = oh->equivalentObjectId; 3576 newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0; 3577 newTags.extraObjectType = in->variantType; 3578 3579 yaffs_VerifyObjectHeader(in,oh,&newTags,1); 3580 3581 /* Create new chunk in NAND */ 3582 newChunkId = 3583 yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags, 3584 (prevChunkId >= 0) ? 1 : 0); 3585 3586 if (newChunkId >= 0) { 3587 3588 in->chunkId = newChunkId; 3589 3590 if (prevChunkId >= 0) { 3591 yaffs_DeleteChunk(dev, prevChunkId, 1, 3592 __LINE__); 3593 } 3594 3595 if(!yaffs_ObjectHasCachedWriteData(in)) 3596 in->dirty = 0; 3597 3598 /* If this was a shrink, then mark the block that the chunk lives on */ 3599 if (isShrink) { 3600 bi = yaffs_GetBlockInfo(in->myDev, 3601 newChunkId /in->myDev-> nChunksPerBlock); 3602 bi->hasShrinkHeader = 1; 3603 } 3604 3605 } 3606 3607 retVal = newChunkId; 3608 3609 } 3610 3611 if (buffer) 3612 yaffs_ReleaseTempBuffer(dev, buffer, __LINE__); 3613 3614 return retVal; 3615 } 3616 3617 /*------------------------ Short Operations Cache ---------------------------------------- 3618 * In many situations where there is no high level buffering (eg WinCE) a lot of 3619 * reads might be short sequential reads, and a lot of writes may be short 3620 * sequential writes. eg. scanning/writing a jpeg file. 3621 * In these cases, a short read/write cache can provide a huge perfomance benefit 3622 * with dumb-as-a-rock code. 3623 * In Linux, the page cache provides read buffering aand the short op cache provides write 3624 * buffering. 3625 * 3626 * There are a limited number (~10) of cache chunks per device so that we don't 3627 * need a very intelligent search. 3628 */ 3629 3630 static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj) 3631 { 3632 yaffs_Device *dev = obj->myDev; 3633 int i; 3634 yaffs_ChunkCache *cache; 3635 int nCaches = obj->myDev->nShortOpCaches; 3636 3637 for(i = 0; i < nCaches; i++){ 3638 cache = &dev->srCache[i]; 3639 if (cache->object == obj && 3640 cache->dirty) 3641 return 1; 3642 } 3643 3644 return 0; 3645 } 3646 3647 3648 static void yaffs_FlushFilesChunkCache(yaffs_Object * obj) 3649 { 3650 yaffs_Device *dev = obj->myDev; 3651 int lowest = -99; /* Stop compiler whining. */ 3652 int i; 3653 yaffs_ChunkCache *cache; 3654 int chunkWritten = 0; 3655 int nCaches = obj->myDev->nShortOpCaches; 3656 3657 if (nCaches > 0) { 3658 do { 3659 cache = NULL; 3660 3661 /* Find the dirty cache for this object with the lowest chunk id. */ 3662 for (i = 0; i < nCaches; i++) { 3663 if (dev->srCache[i].object == obj && 3664 dev->srCache[i].dirty) { 3665 if (!cache 3666 || dev->srCache[i].chunkId < 3667 lowest) { 3668 cache = &dev->srCache[i]; 3669 lowest = cache->chunkId; 3670 } 3671 } 3672 } 3673 3674 if (cache && !cache->locked) { 3675 /* Write it out and free it up */ 3676 3677 chunkWritten = 3678 yaffs_WriteChunkDataToObject(cache->object, 3679 cache->chunkId, 3680 cache->data, 3681 cache->nBytes, 3682 1); 3683 cache->dirty = 0; 3684 cache->object = NULL; 3685 } 3686 3687 } while (cache && chunkWritten > 0); 3688 3689 if (cache) { 3690 /* Hoosterman, disk full while writing cache out. */ 3691 T(YAFFS_TRACE_ERROR, 3692 (TSTR("yaffs tragedy: no space during cache write" TENDSTR))); 3693 3694 } 3695 } 3696 3697 } 3698 3699 /*yaffs_FlushEntireDeviceCache(dev) 3700 * 3701 * 3702 */ 3703 3704 void yaffs_FlushEntireDeviceCache(yaffs_Device *dev) 3705 { 3706 yaffs_Object *obj; 3707 int nCaches = dev->nShortOpCaches; 3708 int i; 3709 3710 /* Find a dirty object in the cache and flush it... 3711 * until there are no further dirty objects. 3712 */ 3713 do { 3714 obj = NULL; 3715 for( i = 0; i < nCaches && !obj; i++) { 3716 if (dev->srCache[i].object && 3717 dev->srCache[i].dirty) 3718 obj = dev->srCache[i].object; 3719 3720 } 3721 if(obj) 3722 yaffs_FlushFilesChunkCache(obj); 3723 3724 } while(obj); 3725 3726 } 3727 3728 3729 /* Grab us a cache chunk for use. 3730 * First look for an empty one. 3731 * Then look for the least recently used non-dirty one. 3732 * Then look for the least recently used dirty one...., flush and look again. 3733 */ 3734 static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device * dev) 3735 { 3736 int i; 3737 int usage; 3738 int theOne; 3739 3740 if (dev->nShortOpCaches > 0) { 3741 for (i = 0; i < dev->nShortOpCaches; i++) { 3742 if (!dev->srCache[i].object) 3743 return &dev->srCache[i]; 3744 } 3745 3746 return NULL; 3747 3748 theOne = -1; 3749 usage = 0; /* just to stop the compiler grizzling */ 3750 3751 for (i = 0; i < dev->nShortOpCaches; i++) { 3752 if (!dev->srCache[i].dirty && 3753 ((dev->srCache[i].lastUse < usage && theOne >= 0) || 3754 theOne < 0)) { 3755 usage = dev->srCache[i].lastUse; 3756 theOne = i; 3757 } 3758 } 3759 3760 3761 return theOne >= 0 ? &dev->srCache[theOne] : NULL; 3762 } else { 3763 return NULL; 3764 } 3765 3766 } 3767 3768 static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device * dev) 3769 { 3770 yaffs_ChunkCache *cache; 3771 yaffs_Object *theObj; 3772 int usage; 3773 int i; 3774 int pushout; 3775 3776 if (dev->nShortOpCaches > 0) { 3777 /* Try find a non-dirty one... */ 3778 3779 cache = yaffs_GrabChunkCacheWorker(dev); 3780 3781 if (!cache) { 3782 /* They were all dirty, find the last recently used object and flush 3783 * its cache, then find again. 3784 * NB what's here is not very accurate, we actually flush the object 3785 * the last recently used page. 3786 */ 3787 3788 /* With locking we can't assume we can use entry zero */ 3789 3790 theObj = NULL; 3791 usage = -1; 3792 cache = NULL; 3793 pushout = -1; 3794 3795 for (i = 0; i < dev->nShortOpCaches; i++) { 3796 if (dev->srCache[i].object && 3797 !dev->srCache[i].locked && 3798 (dev->srCache[i].lastUse < usage || !cache)) 3799 { 3800 usage = dev->srCache[i].lastUse; 3801 theObj = dev->srCache[i].object; 3802 cache = &dev->srCache[i]; 3803 pushout = i; 3804 } 3805 } 3806 3807 if (!cache || cache->dirty) { 3808 /* Flush and try again */ 3809 yaffs_FlushFilesChunkCache(theObj); 3810 cache = yaffs_GrabChunkCacheWorker(dev); 3811 } 3812 3813 } 3814 return cache; 3815 } else 3816 return NULL; 3817 3818 } 3819 3820 /* Find a cached chunk */ 3821 static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object * obj, 3822 int chunkId) 3823 { 3824 yaffs_Device *dev = obj->myDev; 3825 int i; 3826 if (dev->nShortOpCaches > 0) { 3827 for (i = 0; i < dev->nShortOpCaches; i++) { 3828 if (dev->srCache[i].object == obj && 3829 dev->srCache[i].chunkId == chunkId) { 3830 dev->cacheHits++; 3831 3832 return &dev->srCache[i]; 3833 } 3834 } 3835 } 3836 return NULL; 3837 } 3838 3839 /* Mark the chunk for the least recently used algorithym */ 3840 static void yaffs_UseChunkCache(yaffs_Device * dev, yaffs_ChunkCache * cache, 3841 int isAWrite) 3842 { 3843 3844 if (dev->nShortOpCaches > 0) { 3845 if (dev->srLastUse < 0 || dev->srLastUse > 100000000) { 3846 /* Reset the cache usages */ 3847 int i; 3848 for (i = 1; i < dev->nShortOpCaches; i++) { 3849 dev->srCache[i].lastUse = 0; 3850 } 3851 dev->srLastUse = 0; 3852 } 3853 3854 dev->srLastUse++; 3855 3856 cache->lastUse = dev->srLastUse; 3857 3858 if (isAWrite) { 3859 cache->dirty = 1; 3860 } 3861 } 3862 } 3863 3864 /* Invalidate a single cache page. 3865 * Do this when a whole page gets written, 3866 * ie the short cache for this page is no longer valid. 3867 */ 3868 static void yaffs_InvalidateChunkCache(yaffs_Object * object, int chunkId) 3869 { 3870 if (object->myDev->nShortOpCaches > 0) { 3871 yaffs_ChunkCache *cache = yaffs_FindChunkCache(object, chunkId); 3872 3873 if (cache) { 3874 cache->object = NULL; 3875 } 3876 } 3877 } 3878 3879 /* Invalidate all the cache pages associated with this object 3880 * Do this whenever ther file is deleted or resized. 3881 */ 3882 static void yaffs_InvalidateWholeChunkCache(yaffs_Object * in) 3883 { 3884 int i; 3885 yaffs_Device *dev = in->myDev; 3886 3887 if (dev->nShortOpCaches > 0) { 3888 /* Invalidate it. */ 3889 for (i = 0; i < dev->nShortOpCaches; i++) { 3890 if (dev->srCache[i].object == in) { 3891 dev->srCache[i].object = NULL; 3892 } 3893 } 3894 } 3895 } 3896 3897 /*--------------------- Checkpointing --------------------*/ 3898 3899 3900 static int yaffs_WriteCheckpointValidityMarker(yaffs_Device *dev,int head) 3901 { 3902 yaffs_CheckpointValidity cp; 3903 3904 memset(&cp,0,sizeof(cp)); 3905 3906 cp.structType = sizeof(cp); 3907 cp.magic = YAFFS_MAGIC; 3908 cp.version = YAFFS_CHECKPOINT_VERSION; 3909 cp.head = (head) ? 1 : 0; 3910 3911 return (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp))? 3912 1 : 0; 3913 } 3914 3915 static int yaffs_ReadCheckpointValidityMarker(yaffs_Device *dev, int head) 3916 { 3917 yaffs_CheckpointValidity cp; 3918 int ok; 3919 3920 ok = (yaffs_CheckpointRead(dev,&cp,sizeof(cp)) == sizeof(cp)); 3921 3922 if(ok) 3923 ok = (cp.structType == sizeof(cp)) && 3924 (cp.magic == YAFFS_MAGIC) && 3925 (cp.version == YAFFS_CHECKPOINT_VERSION) && 3926 (cp.head == ((head) ? 1 : 0)); 3927 return ok ? 1 : 0; 3928 } 3929 3930 static void yaffs_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp, 3931 yaffs_Device *dev) 3932 { 3933 cp->nErasedBlocks = dev->nErasedBlocks; 3934 cp->allocationBlock = dev->allocationBlock; 3935 cp->allocationPage = dev->allocationPage; 3936 cp->nFreeChunks = dev->nFreeChunks; 3937 3938 cp->nDeletedFiles = dev->nDeletedFiles; 3939 cp->nUnlinkedFiles = dev->nUnlinkedFiles; 3940 cp->nBackgroundDeletions = dev->nBackgroundDeletions; 3941 cp->sequenceNumber = dev->sequenceNumber; 3942 cp->oldestDirtySequence = dev->oldestDirtySequence; 3943 3944 } 3945 3946 static void yaffs_CheckpointDeviceToDevice(yaffs_Device *dev, 3947 yaffs_CheckpointDevice *cp) 3948 { 3949 dev->nErasedBlocks = cp->nErasedBlocks; 3950 dev->allocationBlock = cp->allocationBlock; 3951 dev->allocationPage = cp->allocationPage; 3952 dev->nFreeChunks = cp->nFreeChunks; 3953 3954 dev->nDeletedFiles = cp->nDeletedFiles; 3955 dev->nUnlinkedFiles = cp->nUnlinkedFiles; 3956 dev->nBackgroundDeletions = cp->nBackgroundDeletions; 3957 dev->sequenceNumber = cp->sequenceNumber; 3958 dev->oldestDirtySequence = cp->oldestDirtySequence; 3959 } 3960 3961 3962 static int yaffs_WriteCheckpointDevice(yaffs_Device *dev) 3963 { 3964 yaffs_CheckpointDevice cp; 3965 __u32 nBytes; 3966 __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1); 3967 3968 int ok; 3969 3970 /* Write device runtime values*/ 3971 yaffs_DeviceToCheckpointDevice(&cp,dev); 3972 cp.structType = sizeof(cp); 3973 3974 ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp)); 3975 3976 /* Write block info */ 3977 if(ok) { 3978 nBytes = nBlocks * sizeof(yaffs_BlockInfo); 3979 ok = (yaffs_CheckpointWrite(dev,dev->blockInfo,nBytes) == nBytes); 3980 } 3981 3982 /* Write chunk bits */ 3983 if(ok) { 3984 nBytes = nBlocks * dev->chunkBitmapStride; 3985 ok = (yaffs_CheckpointWrite(dev,dev->chunkBits,nBytes) == nBytes); 3986 } 3987 return ok ? 1 : 0; 3988 3989 } 3990 3991 static int yaffs_ReadCheckpointDevice(yaffs_Device *dev) 3992 { 3993 yaffs_CheckpointDevice cp; 3994 __u32 nBytes; 3995 __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1); 3996 3997 int ok; 3998 3999 ok = (yaffs_CheckpointRead(dev,&cp,sizeof(cp)) == sizeof(cp)); 4000 if(!ok) 4001 return 0; 4002 4003 if(cp.structType != sizeof(cp)) 4004 return 0; 4005 4006 4007 yaffs_CheckpointDeviceToDevice(dev,&cp); 4008 4009 nBytes = nBlocks * sizeof(yaffs_BlockInfo); 4010 4011 ok = (yaffs_CheckpointRead(dev,dev->blockInfo,nBytes) == nBytes); 4012 4013 if(!ok) 4014 return 0; 4015 nBytes = nBlocks * dev->chunkBitmapStride; 4016 4017 ok = (yaffs_CheckpointRead(dev,dev->chunkBits,nBytes) == nBytes); 4018 4019 return ok ? 1 : 0; 4020 } 4021 4022 static void yaffs_ObjectToCheckpointObject(yaffs_CheckpointObject *cp, 4023 yaffs_Object *obj) 4024 { 4025 4026 cp->objectId = obj->objectId; 4027 cp->parentId = (obj->parent) ? obj->parent->objectId : 0; 4028 cp->chunkId = obj->chunkId; 4029 cp->variantType = obj->variantType; 4030 cp->deleted = obj->deleted; 4031 cp->softDeleted = obj->softDeleted; 4032 cp->unlinked = obj->unlinked; 4033 cp->fake = obj->fake; 4034 cp->renameAllowed = obj->renameAllowed; 4035 cp->unlinkAllowed = obj->unlinkAllowed; 4036 cp->serial = obj->serial; 4037 cp->nDataChunks = obj->nDataChunks; 4038 4039 if(obj->variantType == YAFFS_OBJECT_TYPE_FILE) 4040 cp->fileSizeOrEquivalentObjectId = obj->variant.fileVariant.fileSize; 4041 else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) 4042 cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId; 4043 } 4044 4045 static void yaffs_CheckpointObjectToObject( yaffs_Object *obj,yaffs_CheckpointObject *cp) 4046 { 4047 4048 yaffs_Object *parent; 4049 4050 obj->objectId = cp->objectId; 4051 4052 if(cp->parentId) 4053 parent = yaffs_FindOrCreateObjectByNumber( 4054 obj->myDev, 4055 cp->parentId, 4056 YAFFS_OBJECT_TYPE_DIRECTORY); 4057 else 4058 parent = NULL; 4059 4060 if(parent) 4061 yaffs_AddObjectToDirectory(parent, obj); 4062 4063 obj->chunkId = cp->chunkId; 4064 obj->variantType = cp->variantType; 4065 obj->deleted = cp->deleted; 4066 obj->softDeleted = cp->softDeleted; 4067 obj->unlinked = cp->unlinked; 4068 obj->fake = cp->fake; 4069 obj->renameAllowed = cp->renameAllowed; 4070 obj->unlinkAllowed = cp->unlinkAllowed; 4071 obj->serial = cp->serial; 4072 obj->nDataChunks = cp->nDataChunks; 4073 4074 if(obj->variantType == YAFFS_OBJECT_TYPE_FILE) 4075 obj->variant.fileVariant.fileSize = cp->fileSizeOrEquivalentObjectId; 4076 else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) 4077 obj->variant.hardLinkVariant.equivalentObjectId = cp->fileSizeOrEquivalentObjectId; 4078 4079 if(obj->objectId >= YAFFS_NOBJECT_BUCKETS) 4080 obj->lazyLoaded = 1; 4081 } 4082 4083 4084 4085 static int yaffs_CheckpointTnodeWorker(yaffs_Object * in, yaffs_Tnode * tn, 4086 __u32 level, int chunkOffset) 4087 { 4088 int i; 4089 yaffs_Device *dev = in->myDev; 4090 int ok = 1; 4091 int nTnodeBytes = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; 4092 4093 if (tn) { 4094 if (level > 0) { 4095 4096 for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++){ 4097 if (tn->internal[i]) { 4098 ok = yaffs_CheckpointTnodeWorker(in, 4099 tn->internal[i], 4100 level - 1, 4101 (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i); 4102 } 4103 } 4104 } else if (level == 0) { 4105 __u32 baseOffset = chunkOffset << YAFFS_TNODES_LEVEL0_BITS; 4106 /* printf("write tnode at %d\n",baseOffset); */ 4107 ok = (yaffs_CheckpointWrite(dev,&baseOffset,sizeof(baseOffset)) == sizeof(baseOffset)); 4108 if(ok) 4109 ok = (yaffs_CheckpointWrite(dev,tn,nTnodeBytes) == nTnodeBytes); 4110 } 4111 } 4112 4113 return ok; 4114 4115 } 4116 4117 static int yaffs_WriteCheckpointTnodes(yaffs_Object *obj) 4118 { 4119 __u32 endMarker = ~0; 4120 int ok = 1; 4121 4122 if(obj->variantType == YAFFS_OBJECT_TYPE_FILE){ 4123 ok = yaffs_CheckpointTnodeWorker(obj, 4124 obj->variant.fileVariant.top, 4125 obj->variant.fileVariant.topLevel, 4126 0); 4127 if(ok) 4128 ok = (yaffs_CheckpointWrite(obj->myDev,&endMarker,sizeof(endMarker)) == 4129 sizeof(endMarker)); 4130 } 4131 4132 return ok ? 1 : 0; 4133 } 4134 4135 static int yaffs_ReadCheckpointTnodes(yaffs_Object *obj) 4136 { 4137 __u32 baseChunk; 4138 int ok = 1; 4139 yaffs_Device *dev = obj->myDev; 4140 yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant; 4141 yaffs_Tnode *tn; 4142 int nread = 0; 4143 4144 ok = (yaffs_CheckpointRead(dev,&baseChunk,sizeof(baseChunk)) == sizeof(baseChunk)); 4145 4146 while(ok && (~baseChunk)){ 4147 nread++; 4148 /* Read level 0 tnode */ 4149 4150 4151 /* printf("read tnode at %d\n",baseChunk); */ 4152 tn = yaffs_GetTnodeRaw(dev); 4153 if(tn) 4154 ok = (yaffs_CheckpointRead(dev,tn,(dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8) == 4155 (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8); 4156 else 4157 ok = 0; 4158 4159 if(tn && ok){ 4160 ok = yaffs_AddOrFindLevel0Tnode(dev, 4161 fileStructPtr, 4162 baseChunk, 4163 tn) ? 1 : 0; 4164 4165 } 4166 4167 if(ok) 4168 ok = (yaffs_CheckpointRead(dev,&baseChunk,sizeof(baseChunk)) == sizeof(baseChunk)); 4169 4170 } 4171 4172 T(YAFFS_TRACE_CHECKPOINT,( 4173 TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR), 4174 nread,baseChunk,ok)); 4175 4176 return ok ? 1 : 0; 4177 } 4178 4179 4180 static int yaffs_WriteCheckpointObjects(yaffs_Device *dev) 4181 { 4182 yaffs_Object *obj; 4183 yaffs_CheckpointObject cp; 4184 int i; 4185 int ok = 1; 4186 struct list_head *lh; 4187 4188 4189 /* Iterate through the objects in each hash entry, 4190 * dumping them to the checkpointing stream. 4191 */ 4192 4193 for(i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++){ 4194 list_for_each(lh, &dev->objectBucket[i].list) { 4195 if (lh) { 4196 obj = list_entry(lh, yaffs_Object, hashLink); 4197 if (!obj->deferedFree) { 4198 yaffs_ObjectToCheckpointObject(&cp,obj); 4199 cp.structType = sizeof(cp); 4200 4201 T(YAFFS_TRACE_CHECKPOINT,( 4202 TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %x" TENDSTR), 4203 cp.objectId,cp.parentId,cp.variantType,cp.chunkId,(unsigned) obj)); 4204 4205 ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp)); 4206 4207 if(ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE){ 4208 ok = yaffs_WriteCheckpointTnodes(obj); 4209 } 4210 } 4211 } 4212 } 4213 } 4214 4215 /* Dump end of list */ 4216 memset(&cp,0xFF,sizeof(yaffs_CheckpointObject)); 4217 cp.structType = sizeof(cp); 4218 4219 if(ok) 4220 ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp)); 4221 4222 return ok ? 1 : 0; 4223 } 4224 4225 static int yaffs_ReadCheckpointObjects(yaffs_Device *dev) 4226 { 4227 yaffs_Object *obj; 4228 yaffs_CheckpointObject cp; 4229 int ok = 1; 4230 int done = 0; 4231 yaffs_Object *hardList = NULL; 4232 4233 while(ok && !done) { 4234 ok = (yaffs_CheckpointRead(dev,&cp,sizeof(cp)) == sizeof(cp)); 4235 if(cp.structType != sizeof(cp)) { 4236 T(YAFFS_TRACE_CHECKPOINT,(TSTR("struct size %d instead of %d ok %d"TENDSTR), 4237 cp.structType,sizeof(cp),ok)); 4238 ok = 0; 4239 } 4240 4241 T(YAFFS_TRACE_CHECKPOINT,(TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR), 4242 cp.objectId,cp.parentId,cp.variantType,cp.chunkId)); 4243 4244 if(ok && cp.objectId == ~0) 4245 done = 1; 4246 else if(ok){ 4247 obj = yaffs_FindOrCreateObjectByNumber(dev,cp.objectId, cp.variantType); 4248 if(obj) { 4249 yaffs_CheckpointObjectToObject(obj,&cp); 4250 if(obj->variantType == YAFFS_OBJECT_TYPE_FILE) { 4251 ok = yaffs_ReadCheckpointTnodes(obj); 4252 } else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) { 4253 obj->hardLinks.next = 4254 (struct list_head *) 4255 hardList; 4256 hardList = obj; 4257 } 4258 4259 } 4260 } 4261 } 4262 4263 if(ok) 4264 yaffs_HardlinkFixup(dev,hardList); 4265 4266 return ok ? 1 : 0; 4267 } 4268 4269 static int yaffs_WriteCheckpointSum(yaffs_Device *dev) 4270 { 4271 __u32 checkpointSum; 4272 int ok; 4273 4274 yaffs_GetCheckpointSum(dev,&checkpointSum); 4275 4276 ok = (yaffs_CheckpointWrite(dev,&checkpointSum,sizeof(checkpointSum)) == sizeof(checkpointSum)); 4277 4278 if(!ok) 4279 return 0; 4280 4281 return 1; 4282 } 4283 4284 static int yaffs_ReadCheckpointSum(yaffs_Device *dev) 4285 { 4286 __u32 checkpointSum0; 4287 __u32 checkpointSum1; 4288 int ok; 4289 4290 yaffs_GetCheckpointSum(dev,&checkpointSum0); 4291 4292 ok = (yaffs_CheckpointRead(dev,&checkpointSum1,sizeof(checkpointSum1)) == sizeof(checkpointSum1)); 4293 4294 if(!ok) 4295 return 0; 4296 4297 if(checkpointSum0 != checkpointSum1) 4298 return 0; 4299 4300 return 1; 4301 } 4302 4303 4304 static int yaffs_WriteCheckpointData(yaffs_Device *dev) 4305 { 4306 4307 int ok = 1; 4308 4309 if(dev->skipCheckpointWrite || !dev->isYaffs2){ 4310 T(YAFFS_TRACE_CHECKPOINT,(TSTR("skipping checkpoint write" TENDSTR))); 4311 ok = 0; 4312 } 4313 4314 if(ok) 4315 ok = yaffs_CheckpointOpen(dev,1); 4316 4317 if(ok){ 4318 T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint validity" TENDSTR))); 4319 ok = yaffs_WriteCheckpointValidityMarker(dev,1); 4320 } 4321 if(ok){ 4322 T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint device" TENDSTR))); 4323 ok = yaffs_WriteCheckpointDevice(dev); 4324 } 4325 if(ok){ 4326 T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint objects" TENDSTR))); 4327 ok = yaffs_WriteCheckpointObjects(dev); 4328 } 4329 if(ok){ 4330 T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint validity" TENDSTR))); 4331 ok = yaffs_WriteCheckpointValidityMarker(dev,0); 4332 } 4333 4334 if(ok){ 4335 ok = yaffs_WriteCheckpointSum(dev); 4336 } 4337 4338 4339 if(!yaffs_CheckpointClose(dev)) 4340 ok = 0; 4341 4342 if(ok) 4343 dev->isCheckpointed = 1; 4344 else 4345 dev->isCheckpointed = 0; 4346 4347 return dev->isCheckpointed; 4348 } 4349 4350 static int yaffs_ReadCheckpointData(yaffs_Device *dev) 4351 { 4352 int ok = 1; 4353 4354 if(dev->skipCheckpointRead || !dev->isYaffs2){ 4355 T(YAFFS_TRACE_CHECKPOINT,(TSTR("skipping checkpoint read" TENDSTR))); 4356 ok = 0; 4357 } 4358 4359 if(ok) 4360 ok = yaffs_CheckpointOpen(dev,0); /* open for read */ 4361 4362 if(ok){ 4363 T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint validity" TENDSTR))); 4364 ok = yaffs_ReadCheckpointValidityMarker(dev,1); 4365 } 4366 if(ok){ 4367 T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint device" TENDSTR))); 4368 ok = yaffs_ReadCheckpointDevice(dev); 4369 } 4370 if(ok){ 4371 T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint objects" TENDSTR))); 4372 ok = yaffs_ReadCheckpointObjects(dev); 4373 } 4374 if(ok){ 4375 T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint validity" TENDSTR))); 4376 ok = yaffs_ReadCheckpointValidityMarker(dev,0); 4377 } 4378 4379 if(ok){ 4380 ok = yaffs_ReadCheckpointSum(dev); 4381 T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint checksum %d" TENDSTR),ok)); 4382 } 4383 4384 if(!yaffs_CheckpointClose(dev)) 4385 ok = 0; 4386 4387 if(ok) 4388 dev->isCheckpointed = 1; 4389 else 4390 dev->isCheckpointed = 0; 4391 4392 return ok ? 1 : 0; 4393 4394 } 4395 4396 static void yaffs_InvalidateCheckpoint(yaffs_Device *dev) 4397 { 4398 if(dev->isCheckpointed || 4399 dev->blocksInCheckpoint > 0){ 4400 dev->isCheckpointed = 0; 4401 yaffs_CheckpointInvalidateStream(dev); 4402 if(dev->superBlock && dev->markSuperBlockDirty) 4403 dev->markSuperBlockDirty(dev->superBlock); 4404 } 4405 } 4406 4407 4408 int yaffs_CheckpointSave(yaffs_Device *dev) 4409 { 4410 4411 T(YAFFS_TRACE_CHECKPOINT,(TSTR("save entry: isCheckpointed %d"TENDSTR),dev->isCheckpointed)); 4412 4413 yaffs_VerifyObjects(dev); 4414 yaffs_VerifyBlocks(dev); 4415 yaffs_VerifyFreeChunks(dev); 4416 4417 if(!dev->isCheckpointed) { 4418 yaffs_InvalidateCheckpoint(dev); 4419 yaffs_WriteCheckpointData(dev); 4420 } 4421 4422 T(YAFFS_TRACE_ALWAYS,(TSTR("save exit: isCheckpointed %d"TENDSTR),dev->isCheckpointed)); 4423 4424 return dev->isCheckpointed; 4425 } 4426 4427 int yaffs_CheckpointRestore(yaffs_Device *dev) 4428 { 4429 int retval; 4430 T(YAFFS_TRACE_CHECKPOINT,(TSTR("restore entry: isCheckpointed %d"TENDSTR),dev->isCheckpointed)); 4431 4432 retval = yaffs_ReadCheckpointData(dev); 4433 4434 if(dev->isCheckpointed){ 4435 yaffs_VerifyObjects(dev); 4436 yaffs_VerifyBlocks(dev); 4437 yaffs_VerifyFreeChunks(dev); 4438 } 4439 4440 T(YAFFS_TRACE_CHECKPOINT,(TSTR("restore exit: isCheckpointed %d"TENDSTR),dev->isCheckpointed)); 4441 4442 return retval; 4443 } 4444 4445 /*--------------------- File read/write ------------------------ 4446 * Read and write have very similar structures. 4447 * In general the read/write has three parts to it 4448 * An incomplete chunk to start with (if the read/write is not chunk-aligned) 4449 * Some complete chunks 4450 * An incomplete chunk to end off with 4451 * 4452 * Curve-balls: the first chunk might also be the last chunk. 4453 */ 4454 4455 int yaffs_ReadDataFromFile(yaffs_Object * in, __u8 * buffer, loff_t offset, 4456 int nBytes) 4457 { 4458 4459 __u32 chunk = 0; 4460 __u32 start = 0; 4461 int nToCopy; 4462 int n = nBytes; 4463 int nDone = 0; 4464 yaffs_ChunkCache *cache; 4465 4466 yaffs_Device *dev; 4467 4468 dev = in->myDev; 4469 4470 while (n > 0) { 4471 //chunk = offset / dev->nDataBytesPerChunk + 1; 4472 //start = offset % dev->nDataBytesPerChunk; 4473 yaffs_AddrToChunk(dev,offset,&chunk,&start); 4474 chunk++; 4475 4476 /* OK now check for the curveball where the start and end are in 4477 * the same chunk. 4478 */ 4479 if ((start + n) < dev->nDataBytesPerChunk) { 4480 nToCopy = n; 4481 } else { 4482 nToCopy = dev->nDataBytesPerChunk - start; 4483 } 4484 4485 cache = yaffs_FindChunkCache(in, chunk); 4486 4487 /* If the chunk is already in the cache or it is less than a whole chunk 4488 * then use the cache (if there is caching) 4489 * else bypass the cache. 4490 */ 4491 if (cache || nToCopy != dev->nDataBytesPerChunk) { 4492 if (dev->nShortOpCaches > 0) { 4493 4494 /* If we can't find the data in the cache, then load it up. */ 4495 4496 if (!cache) { 4497 cache = yaffs_GrabChunkCache(in->myDev); 4498 cache->object = in; 4499 cache->chunkId = chunk; 4500 cache->dirty = 0; 4501 cache->locked = 0; 4502 yaffs_ReadChunkDataFromObject(in, chunk, 4503 cache-> 4504 data); 4505 cache->nBytes = 0; 4506 } 4507 4508 yaffs_UseChunkCache(dev, cache, 0); 4509 4510 cache->locked = 1; 4511 4512 #ifdef CONFIG_YAFFS_WINCE 4513 yfsd_UnlockYAFFS(TRUE); 4514 #endif 4515 memcpy(buffer, &cache->data[start], nToCopy); 4516 4517 #ifdef CONFIG_YAFFS_WINCE 4518 yfsd_LockYAFFS(TRUE); 4519 #endif 4520 cache->locked = 0; 4521 } else { 4522 /* Read into the local buffer then copy..*/ 4523 4524 __u8 *localBuffer = 4525 yaffs_GetTempBuffer(dev, __LINE__); 4526 yaffs_ReadChunkDataFromObject(in, chunk, 4527 localBuffer); 4528 #ifdef CONFIG_YAFFS_WINCE 4529 yfsd_UnlockYAFFS(TRUE); 4530 #endif 4531 memcpy(buffer, &localBuffer[start], nToCopy); 4532 4533 #ifdef CONFIG_YAFFS_WINCE 4534 yfsd_LockYAFFS(TRUE); 4535 #endif 4536 yaffs_ReleaseTempBuffer(dev, localBuffer, 4537 __LINE__); 4538 } 4539 4540 } else { 4541 #ifdef CONFIG_YAFFS_WINCE 4542 __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__); 4543 4544 /* Under WinCE can't do direct transfer. Need to use a local buffer. 4545 * This is because we otherwise screw up WinCE's memory mapper 4546 */ 4547 yaffs_ReadChunkDataFromObject(in, chunk, localBuffer); 4548 4549 #ifdef CONFIG_YAFFS_WINCE 4550 yfsd_UnlockYAFFS(TRUE); 4551 #endif 4552 memcpy(buffer, localBuffer, dev->nDataBytesPerChunk); 4553 4554 #ifdef CONFIG_YAFFS_WINCE 4555 yfsd_LockYAFFS(TRUE); 4556 yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__); 4557 #endif 4558 4559 #else 4560 /* A full chunk. Read directly into the supplied buffer. */ 4561 yaffs_ReadChunkDataFromObject(in, chunk, buffer); 4562 #endif 4563 } 4564 4565 n -= nToCopy; 4566 offset += nToCopy; 4567 buffer += nToCopy; 4568 nDone += nToCopy; 4569 4570 } 4571 4572 return nDone; 4573 } 4574 4575 int yaffs_WriteDataToFile(yaffs_Object * in, const __u8 * buffer, loff_t offset, 4576 int nBytes, int writeThrough) 4577 { 4578 4579 __u32 chunk = 0; 4580 __u32 start = 0; 4581 int nToCopy; 4582 int n = nBytes; 4583 int nDone = 0; 4584 int nToWriteBack; 4585 int startOfWrite = offset; 4586 int chunkWritten = 0; 4587 int nBytesRead; 4588 4589 yaffs_Device *dev; 4590 4591 dev = in->myDev; 4592 4593 while (n > 0 && chunkWritten >= 0) { 4594 //chunk = offset / dev->nDataBytesPerChunk + 1; 4595 //start = offset % dev->nDataBytesPerChunk; 4596 yaffs_AddrToChunk(dev,offset,&chunk,&start); 4597 chunk++; 4598 4599 /* OK now check for the curveball where the start and end are in 4600 * the same chunk. 4601 */ 4602 4603 if ((start + n) < dev->nDataBytesPerChunk) { 4604 nToCopy = n; 4605 4606 /* Now folks, to calculate how many bytes to write back.... 4607 * If we're overwriting and not writing to then end of file then 4608 * we need to write back as much as was there before. 4609 */ 4610 4611 nBytesRead = 4612 in->variant.fileVariant.fileSize - 4613 ((chunk - 1) * dev->nDataBytesPerChunk); 4614 4615 if (nBytesRead > dev->nDataBytesPerChunk) { 4616 nBytesRead = dev->nDataBytesPerChunk; 4617 } 4618 4619 nToWriteBack = 4620 (nBytesRead > 4621 (start + n)) ? nBytesRead : (start + n); 4622 4623 } else { 4624 nToCopy = dev->nDataBytesPerChunk - start; 4625 nToWriteBack = dev->nDataBytesPerChunk; 4626 } 4627 4628 if (nToCopy != dev->nDataBytesPerChunk) { 4629 /* An incomplete start or end chunk (or maybe both start and end chunk) */ 4630 if (dev->nShortOpCaches > 0) { 4631 yaffs_ChunkCache *cache; 4632 /* If we can't find the data in the cache, then load the cache */ 4633 cache = yaffs_FindChunkCache(in, chunk); 4634 4635 if (!cache 4636 && yaffs_CheckSpaceForAllocation(in-> 4637 myDev)) { 4638 cache = yaffs_GrabChunkCache(in->myDev); 4639 cache->object = in; 4640 cache->chunkId = chunk; 4641 cache->dirty = 0; 4642 cache->locked = 0; 4643 yaffs_ReadChunkDataFromObject(in, chunk, 4644 cache-> 4645 data); 4646 } 4647 else if(cache && 4648 !cache->dirty && 4649 !yaffs_CheckSpaceForAllocation(in->myDev)){ 4650 /* Drop the cache if it was a read cache item and 4651 * no space check has been made for it. 4652 */ 4653 cache = NULL; 4654 } 4655 4656 if (cache) { 4657 yaffs_UseChunkCache(dev, cache, 1); 4658 cache->locked = 1; 4659 #ifdef CONFIG_YAFFS_WINCE 4660 yfsd_UnlockYAFFS(TRUE); 4661 #endif 4662 4663 memcpy(&cache->data[start], buffer, 4664 nToCopy); 4665 4666 #ifdef CONFIG_YAFFS_WINCE 4667 yfsd_LockYAFFS(TRUE); 4668 #endif 4669 cache->locked = 0; 4670 cache->nBytes = nToWriteBack; 4671 4672 if (writeThrough) { 4673 chunkWritten = 4674 yaffs_WriteChunkDataToObject 4675 (cache->object, 4676 cache->chunkId, 4677 cache->data, cache->nBytes, 4678 1); 4679 cache->dirty = 0; 4680 } 4681 4682 } else { 4683 chunkWritten = -1; /* fail the write */ 4684 } 4685 } else { 4686 /* An incomplete start or end chunk (or maybe both start and end chunk) 4687 * Read into the local buffer then copy, then copy over and write back. 4688 */ 4689 4690 __u8 *localBuffer = 4691 yaffs_GetTempBuffer(dev, __LINE__); 4692 4693 yaffs_ReadChunkDataFromObject(in, chunk, 4694 localBuffer); 4695 4696 #ifdef CONFIG_YAFFS_WINCE 4697 yfsd_UnlockYAFFS(TRUE); 4698 #endif 4699 4700 memcpy(&localBuffer[start], buffer, nToCopy); 4701 4702 #ifdef CONFIG_YAFFS_WINCE 4703 yfsd_LockYAFFS(TRUE); 4704 #endif 4705 chunkWritten = 4706 yaffs_WriteChunkDataToObject(in, chunk, 4707 localBuffer, 4708 nToWriteBack, 4709 0); 4710 4711 yaffs_ReleaseTempBuffer(dev, localBuffer, 4712 __LINE__); 4713 4714 } 4715 4716 } else { 4717 4718 #ifdef CONFIG_YAFFS_WINCE 4719 /* Under WinCE can't do direct transfer. Need to use a local buffer. 4720 * This is because we otherwise screw up WinCE's memory mapper 4721 */ 4722 __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__); 4723 #ifdef CONFIG_YAFFS_WINCE 4724 yfsd_UnlockYAFFS(TRUE); 4725 #endif 4726 memcpy(localBuffer, buffer, dev->nDataBytesPerChunk); 4727 #ifdef CONFIG_YAFFS_WINCE 4728 yfsd_LockYAFFS(TRUE); 4729 #endif 4730 chunkWritten = 4731 yaffs_WriteChunkDataToObject(in, chunk, localBuffer, 4732 dev->nDataBytesPerChunk, 4733 0); 4734 yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__); 4735 #else 4736 /* A full chunk. Write directly from the supplied buffer. */ 4737 chunkWritten = 4738 yaffs_WriteChunkDataToObject(in, chunk, buffer, 4739 dev->nDataBytesPerChunk, 4740 0); 4741 #endif 4742 /* Since we've overwritten the cached data, we better invalidate it. */ 4743 yaffs_InvalidateChunkCache(in, chunk); 4744 } 4745 4746 if (chunkWritten >= 0) { 4747 n -= nToCopy; 4748 offset += nToCopy; 4749 buffer += nToCopy; 4750 nDone += nToCopy; 4751 } 4752 4753 } 4754 4755 /* Update file object */ 4756 4757 if ((startOfWrite + nDone) > in->variant.fileVariant.fileSize) { 4758 in->variant.fileVariant.fileSize = (startOfWrite + nDone); 4759 } 4760 4761 in->dirty = 1; 4762 4763 return nDone; 4764 } 4765 4766 4767 /* ---------------------- File resizing stuff ------------------ */ 4768 4769 static void yaffs_PruneResizedChunks(yaffs_Object * in, int newSize) 4770 { 4771 4772 yaffs_Device *dev = in->myDev; 4773 int oldFileSize = in->variant.fileVariant.fileSize; 4774 4775 int lastDel = 1 + (oldFileSize - 1) / dev->nDataBytesPerChunk; 4776 4777 int startDel = 1 + (newSize + dev->nDataBytesPerChunk - 1) / 4778 dev->nDataBytesPerChunk; 4779 int i; 4780 int chunkId; 4781 4782 /* Delete backwards so that we don't end up with holes if 4783 * power is lost part-way through the operation. 4784 */ 4785 for (i = lastDel; i >= startDel; i--) { 4786 /* NB this could be optimised somewhat, 4787 * eg. could retrieve the tags and write them without 4788 * using yaffs_DeleteChunk 4789 */ 4790 4791 chunkId = yaffs_FindAndDeleteChunkInFile(in, i, NULL); 4792 if (chunkId > 0) { 4793 if (chunkId < 4794 (dev->internalStartBlock * dev->nChunksPerBlock) 4795 || chunkId >= 4796 ((dev->internalEndBlock + 4797 1) * dev->nChunksPerBlock)) { 4798 T(YAFFS_TRACE_ALWAYS, 4799 (TSTR("Found daft chunkId %d for %d" TENDSTR), 4800 chunkId, i)); 4801 } else { 4802 in->nDataChunks--; 4803 yaffs_DeleteChunk(dev, chunkId, 1, __LINE__); 4804 } 4805 } 4806 } 4807 4808 } 4809 4810 int yaffs_ResizeFile(yaffs_Object * in, loff_t newSize) 4811 { 4812 4813 int oldFileSize = in->variant.fileVariant.fileSize; 4814 __u32 newSizeOfPartialChunk = 0; 4815 __u32 newFullChunks = 0; 4816 4817 yaffs_Device *dev = in->myDev; 4818 4819 yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk); 4820 4821 yaffs_FlushFilesChunkCache(in); 4822 yaffs_InvalidateWholeChunkCache(in); 4823 4824 yaffs_CheckGarbageCollection(dev); 4825 4826 if (in->variantType != YAFFS_OBJECT_TYPE_FILE) { 4827 return yaffs_GetFileSize(in); 4828 } 4829 4830 if (newSize == oldFileSize) { 4831 return oldFileSize; 4832 } 4833 4834 if (newSize < oldFileSize) { 4835 4836 yaffs_PruneResizedChunks(in, newSize); 4837 4838 if (newSizeOfPartialChunk != 0) { 4839 int lastChunk = 1 + newFullChunks; 4840 4841 __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__); 4842 4843 /* Got to read and rewrite the last chunk with its new size and zero pad */ 4844 yaffs_ReadChunkDataFromObject(in, lastChunk, 4845 localBuffer); 4846 4847 memset(localBuffer + newSizeOfPartialChunk, 0, 4848 dev->nDataBytesPerChunk - newSizeOfPartialChunk); 4849 4850 yaffs_WriteChunkDataToObject(in, lastChunk, localBuffer, 4851 newSizeOfPartialChunk, 1); 4852 4853 yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__); 4854 } 4855 4856 in->variant.fileVariant.fileSize = newSize; 4857 4858 yaffs_PruneFileStructure(dev, &in->variant.fileVariant); 4859 } else { 4860 /* newsSize > oldFileSize */ 4861 in->variant.fileVariant.fileSize = newSize; 4862 } 4863 4864 4865 4866 /* Write a new object header. 4867 * show we've shrunk the file, if need be 4868 * Do this only if the file is not in the deleted directories. 4869 */ 4870 if (in->parent->objectId != YAFFS_OBJECTID_UNLINKED && 4871 in->parent->objectId != YAFFS_OBJECTID_DELETED) { 4872 yaffs_UpdateObjectHeader(in, NULL, 0, 4873 (newSize < oldFileSize) ? 1 : 0, 0); 4874 } 4875 4876 return YAFFS_OK; 4877 } 4878 4879 loff_t yaffs_GetFileSize(yaffs_Object * obj) 4880 { 4881 obj = yaffs_GetEquivalentObject(obj); 4882 4883 switch (obj->variantType) { 4884 case YAFFS_OBJECT_TYPE_FILE: 4885 return obj->variant.fileVariant.fileSize; 4886 case YAFFS_OBJECT_TYPE_SYMLINK: 4887 return yaffs_strlen(obj->variant.symLinkVariant.alias); 4888 default: 4889 return 0; 4890 } 4891 } 4892 4893 4894 4895 int yaffs_FlushFile(yaffs_Object * in, int updateTime) 4896 { 4897 int retVal; 4898 if (in->dirty) { 4899 yaffs_FlushFilesChunkCache(in); 4900 if (updateTime) { 4901 #ifdef CONFIG_YAFFS_WINCE 4902 yfsd_WinFileTimeNow(in->win_mtime); 4903 #else 4904 4905 in->yst_mtime = Y_CURRENT_TIME; 4906 4907 #endif 4908 } 4909 4910 retVal = 4911 (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0) >= 4912 0) ? YAFFS_OK : YAFFS_FAIL; 4913 } else { 4914 retVal = YAFFS_OK; 4915 } 4916 4917 return retVal; 4918 4919 } 4920 4921 static int yaffs_DoGenericObjectDeletion(yaffs_Object * in) 4922 { 4923 4924 /* First off, invalidate the file's data in the cache, without flushing. */ 4925 yaffs_InvalidateWholeChunkCache(in); 4926 4927 if (in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir)) { 4928 /* Move to the unlinked directory so we have a record that it was deleted. */ 4929 yaffs_ChangeObjectName(in, in->myDev->deletedDir,"deleted", 0, 0); 4930 4931 } 4932 4933 yaffs_RemoveObjectFromDirectory(in); 4934 yaffs_DeleteChunk(in->myDev, in->chunkId, 1, __LINE__); 4935 in->chunkId = -1; 4936 4937 yaffs_FreeObject(in); 4938 return YAFFS_OK; 4939 4940 } 4941 4942 /* yaffs_DeleteFile deletes the whole file data 4943 * and the inode associated with the file. 4944 * It does not delete the links associated with the file. 4945 */ 4946 static int yaffs_UnlinkFile(yaffs_Object * in) 4947 { 4948 4949 int retVal; 4950 int immediateDeletion = 0; 4951 4952 if (1) { 4953 /* XXX U-BOOT XXX */ 4954 #if 0 4955 #ifdef __KERNEL__ 4956 if (!in->myInode) { 4957 immediateDeletion = 1; 4958 4959 } 4960 #endif 4961 #else 4962 if (in->inUse <= 0) { 4963 immediateDeletion = 1; 4964 4965 } 4966 #endif 4967 if (immediateDeletion) { 4968 retVal = 4969 yaffs_ChangeObjectName(in, in->myDev->deletedDir, 4970 "deleted", 0, 0); 4971 T(YAFFS_TRACE_TRACING, 4972 (TSTR("yaffs: immediate deletion of file %d" TENDSTR), 4973 in->objectId)); 4974 in->deleted = 1; 4975 in->myDev->nDeletedFiles++; 4976 if (0 && in->myDev->isYaffs2) { 4977 yaffs_ResizeFile(in, 0); 4978 } 4979 yaffs_SoftDeleteFile(in); 4980 } else { 4981 retVal = 4982 yaffs_ChangeObjectName(in, in->myDev->unlinkedDir, 4983 "unlinked", 0, 0); 4984 } 4985 4986 } 4987 return retVal; 4988 } 4989 4990 int yaffs_DeleteFile(yaffs_Object * in) 4991 { 4992 int retVal = YAFFS_OK; 4993 4994 if (in->nDataChunks > 0) { 4995 /* Use soft deletion if there is data in the file */ 4996 if (!in->unlinked) { 4997 retVal = yaffs_UnlinkFile(in); 4998 } 4999 if (retVal == YAFFS_OK && in->unlinked && !in->deleted) { 5000 in->deleted = 1; 5001 in->myDev->nDeletedFiles++; 5002 yaffs_SoftDeleteFile(in); 5003 } 5004 return in->deleted ? YAFFS_OK : YAFFS_FAIL; 5005 } else { 5006 /* The file has no data chunks so we toss it immediately */ 5007 yaffs_FreeTnode(in->myDev, in->variant.fileVariant.top); 5008 in->variant.fileVariant.top = NULL; 5009 yaffs_DoGenericObjectDeletion(in); 5010 5011 return YAFFS_OK; 5012 } 5013 } 5014 5015 static int yaffs_DeleteDirectory(yaffs_Object * in) 5016 { 5017 /* First check that the directory is empty. */ 5018 if (list_empty(&in->variant.directoryVariant.children)) { 5019 return yaffs_DoGenericObjectDeletion(in); 5020 } 5021 5022 return YAFFS_FAIL; 5023 5024 } 5025 5026 static int yaffs_DeleteSymLink(yaffs_Object * in) 5027 { 5028 YFREE(in->variant.symLinkVariant.alias); 5029 5030 return yaffs_DoGenericObjectDeletion(in); 5031 } 5032 5033 static int yaffs_DeleteHardLink(yaffs_Object * in) 5034 { 5035 /* remove this hardlink from the list assocaited with the equivalent 5036 * object 5037 */ 5038 list_del(&in->hardLinks); 5039 return yaffs_DoGenericObjectDeletion(in); 5040 } 5041 5042 static void yaffs_DestroyObject(yaffs_Object * obj) 5043 { 5044 switch (obj->variantType) { 5045 case YAFFS_OBJECT_TYPE_FILE: 5046 yaffs_DeleteFile(obj); 5047 break; 5048 case YAFFS_OBJECT_TYPE_DIRECTORY: 5049 yaffs_DeleteDirectory(obj); 5050 break; 5051 case YAFFS_OBJECT_TYPE_SYMLINK: 5052 yaffs_DeleteSymLink(obj); 5053 break; 5054 case YAFFS_OBJECT_TYPE_HARDLINK: 5055 yaffs_DeleteHardLink(obj); 5056 break; 5057 case YAFFS_OBJECT_TYPE_SPECIAL: 5058 yaffs_DoGenericObjectDeletion(obj); 5059 break; 5060 case YAFFS_OBJECT_TYPE_UNKNOWN: 5061 break; /* should not happen. */ 5062 } 5063 } 5064 5065 static int yaffs_UnlinkWorker(yaffs_Object * obj) 5066 { 5067 5068 if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) { 5069 return yaffs_DeleteHardLink(obj); 5070 } else if (!list_empty(&obj->hardLinks)) { 5071 /* Curve ball: We're unlinking an object that has a hardlink. 5072 * 5073 * This problem arises because we are not strictly following 5074 * The Linux link/inode model. 5075 * 5076 * We can't really delete the object. 5077 * Instead, we do the following: 5078 * - Select a hardlink. 5079 * - Unhook it from the hard links 5080 * - Unhook it from its parent directory (so that the rename can work) 5081 * - Rename the object to the hardlink's name. 5082 * - Delete the hardlink 5083 */ 5084 5085 yaffs_Object *hl; 5086 int retVal; 5087 YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; 5088 5089 hl = list_entry(obj->hardLinks.next, yaffs_Object, hardLinks); 5090 5091 list_del_init(&hl->hardLinks); 5092 list_del_init(&hl->siblings); 5093 5094 yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1); 5095 5096 retVal = yaffs_ChangeObjectName(obj, hl->parent, name, 0, 0); 5097 5098 if (retVal == YAFFS_OK) { 5099 retVal = yaffs_DoGenericObjectDeletion(hl); 5100 } 5101 return retVal; 5102 5103 } else { 5104 switch (obj->variantType) { 5105 case YAFFS_OBJECT_TYPE_FILE: 5106 return yaffs_UnlinkFile(obj); 5107 break; 5108 case YAFFS_OBJECT_TYPE_DIRECTORY: 5109 return yaffs_DeleteDirectory(obj); 5110 break; 5111 case YAFFS_OBJECT_TYPE_SYMLINK: 5112 return yaffs_DeleteSymLink(obj); 5113 break; 5114 case YAFFS_OBJECT_TYPE_SPECIAL: 5115 return yaffs_DoGenericObjectDeletion(obj); 5116 break; 5117 case YAFFS_OBJECT_TYPE_HARDLINK: 5118 case YAFFS_OBJECT_TYPE_UNKNOWN: 5119 default: 5120 return YAFFS_FAIL; 5121 } 5122 } 5123 } 5124 5125 5126 static int yaffs_UnlinkObject( yaffs_Object *obj) 5127 { 5128 5129 if (obj && obj->unlinkAllowed) { 5130 return yaffs_UnlinkWorker(obj); 5131 } 5132 5133 return YAFFS_FAIL; 5134 5135 } 5136 int yaffs_Unlink(yaffs_Object * dir, const YCHAR * name) 5137 { 5138 yaffs_Object *obj; 5139 5140 obj = yaffs_FindObjectByName(dir, name); 5141 return yaffs_UnlinkObject(obj); 5142 } 5143 5144 /*----------------------- Initialisation Scanning ---------------------- */ 5145 5146 static void yaffs_HandleShadowedObject(yaffs_Device * dev, int objId, 5147 int backwardScanning) 5148 { 5149 yaffs_Object *obj; 5150 5151 if (!backwardScanning) { 5152 /* Handle YAFFS1 forward scanning case 5153 * For YAFFS1 we always do the deletion 5154 */ 5155 5156 } else { 5157 /* Handle YAFFS2 case (backward scanning) 5158 * If the shadowed object exists then ignore. 5159 */ 5160 if (yaffs_FindObjectByNumber(dev, objId)) { 5161 return; 5162 } 5163 } 5164 5165 /* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc. 5166 * We put it in unlinked dir to be cleaned up after the scanning 5167 */ 5168 obj = 5169 yaffs_FindOrCreateObjectByNumber(dev, objId, 5170 YAFFS_OBJECT_TYPE_FILE); 5171 yaffs_AddObjectToDirectory(dev->unlinkedDir, obj); 5172 obj->variant.fileVariant.shrinkSize = 0; 5173 obj->valid = 1; /* So that we don't read any other info for this file */ 5174 5175 } 5176 5177 typedef struct { 5178 int seq; 5179 int block; 5180 } yaffs_BlockIndex; 5181 5182 5183 static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList) 5184 { 5185 yaffs_Object *hl; 5186 yaffs_Object *in; 5187 5188 while (hardList) { 5189 hl = hardList; 5190 hardList = (yaffs_Object *) (hardList->hardLinks.next); 5191 5192 in = yaffs_FindObjectByNumber(dev, 5193 hl->variant.hardLinkVariant. 5194 equivalentObjectId); 5195 5196 if (in) { 5197 /* Add the hardlink pointers */ 5198 hl->variant.hardLinkVariant.equivalentObject = in; 5199 list_add(&hl->hardLinks, &in->hardLinks); 5200 } else { 5201 /* Todo Need to report/handle this better. 5202 * Got a problem... hardlink to a non-existant object 5203 */ 5204 hl->variant.hardLinkVariant.equivalentObject = NULL; 5205 INIT_LIST_HEAD(&hl->hardLinks); 5206 5207 } 5208 5209 } 5210 5211 } 5212 5213 5214 5215 5216 5217 static int ybicmp(const void *a, const void *b){ 5218 register int aseq = ((yaffs_BlockIndex *)a)->seq; 5219 register int bseq = ((yaffs_BlockIndex *)b)->seq; 5220 register int ablock = ((yaffs_BlockIndex *)a)->block; 5221 register int bblock = ((yaffs_BlockIndex *)b)->block; 5222 if( aseq == bseq ) 5223 return ablock - bblock; 5224 else 5225 return aseq - bseq; 5226 5227 } 5228 5229 static int yaffs_Scan(yaffs_Device * dev) 5230 { 5231 yaffs_ExtendedTags tags; 5232 int blk; 5233 int blockIterator; 5234 int startIterator; 5235 int endIterator; 5236 int nBlocksToScan = 0; 5237 int result; 5238 5239 int chunk; 5240 int c; 5241 int deleted; 5242 yaffs_BlockState state; 5243 yaffs_Object *hardList = NULL; 5244 yaffs_BlockInfo *bi; 5245 int sequenceNumber; 5246 yaffs_ObjectHeader *oh; 5247 yaffs_Object *in; 5248 yaffs_Object *parent; 5249 int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1; 5250 5251 int alloc_failed = 0; 5252 5253 5254 __u8 *chunkData; 5255 5256 yaffs_BlockIndex *blockIndex = NULL; 5257 5258 if (dev->isYaffs2) { 5259 T(YAFFS_TRACE_SCAN, 5260 (TSTR("yaffs_Scan is not for YAFFS2!" TENDSTR))); 5261 return YAFFS_FAIL; 5262 } 5263 5264 //TODO Throw all the yaffs2 stuuf out of yaffs_Scan since it is only for yaffs1 format. 5265 5266 T(YAFFS_TRACE_SCAN, 5267 (TSTR("yaffs_Scan starts intstartblk %d intendblk %d..." TENDSTR), 5268 dev->internalStartBlock, dev->internalEndBlock)); 5269 5270 chunkData = yaffs_GetTempBuffer(dev, __LINE__); 5271 5272 dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER; 5273 5274 if (dev->isYaffs2) { 5275 blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex)); 5276 if(!blockIndex) 5277 return YAFFS_FAIL; 5278 } 5279 5280 /* Scan all the blocks to determine their state */ 5281 for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) { 5282 bi = yaffs_GetBlockInfo(dev, blk); 5283 yaffs_ClearChunkBits(dev, blk); 5284 bi->pagesInUse = 0; 5285 bi->softDeletions = 0; 5286 5287 yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber); 5288 5289 bi->blockState = state; 5290 bi->sequenceNumber = sequenceNumber; 5291 5292 T(YAFFS_TRACE_SCAN_DEBUG, 5293 (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk, 5294 state, sequenceNumber)); 5295 5296 if (state == YAFFS_BLOCK_STATE_DEAD) { 5297 T(YAFFS_TRACE_BAD_BLOCKS, 5298 (TSTR("block %d is bad" TENDSTR), blk)); 5299 } else if (state == YAFFS_BLOCK_STATE_EMPTY) { 5300 T(YAFFS_TRACE_SCAN_DEBUG, 5301 (TSTR("Block empty " TENDSTR))); 5302 dev->nErasedBlocks++; 5303 dev->nFreeChunks += dev->nChunksPerBlock; 5304 } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { 5305 5306 /* Determine the highest sequence number */ 5307 if (dev->isYaffs2 && 5308 sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER && 5309 sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) { 5310 5311 blockIndex[nBlocksToScan].seq = sequenceNumber; 5312 blockIndex[nBlocksToScan].block = blk; 5313 5314 nBlocksToScan++; 5315 5316 if (sequenceNumber >= dev->sequenceNumber) { 5317 dev->sequenceNumber = sequenceNumber; 5318 } 5319 } else if (dev->isYaffs2) { 5320 /* TODO: Nasty sequence number! */ 5321 T(YAFFS_TRACE_SCAN, 5322 (TSTR 5323 ("Block scanning block %d has bad sequence number %d" 5324 TENDSTR), blk, sequenceNumber)); 5325 5326 } 5327 } 5328 } 5329 5330 /* Sort the blocks 5331 * Dungy old bubble sort for now... 5332 */ 5333 if (dev->isYaffs2) { 5334 yaffs_BlockIndex temp; 5335 int i; 5336 int j; 5337 5338 for (i = 0; i < nBlocksToScan; i++) 5339 for (j = i + 1; j < nBlocksToScan; j++) 5340 if (blockIndex[i].seq > blockIndex[j].seq) { 5341 temp = blockIndex[j]; 5342 blockIndex[j] = blockIndex[i]; 5343 blockIndex[i] = temp; 5344 } 5345 } 5346 5347 /* Now scan the blocks looking at the data. */ 5348 if (dev->isYaffs2) { 5349 startIterator = 0; 5350 endIterator = nBlocksToScan - 1; 5351 T(YAFFS_TRACE_SCAN_DEBUG, 5352 (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan)); 5353 } else { 5354 startIterator = dev->internalStartBlock; 5355 endIterator = dev->internalEndBlock; 5356 } 5357 5358 /* For each block.... */ 5359 for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator; 5360 blockIterator++) { 5361 5362 if (dev->isYaffs2) { 5363 /* get the block to scan in the correct order */ 5364 blk = blockIndex[blockIterator].block; 5365 } else { 5366 blk = blockIterator; 5367 } 5368 5369 bi = yaffs_GetBlockInfo(dev, blk); 5370 state = bi->blockState; 5371 5372 deleted = 0; 5373 5374 /* For each chunk in each block that needs scanning....*/ 5375 for (c = 0; !alloc_failed && c < dev->nChunksPerBlock && 5376 state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) { 5377 /* Read the tags and decide what to do */ 5378 chunk = blk * dev->nChunksPerBlock + c; 5379 5380 result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL, 5381 &tags); 5382 5383 /* Let's have a good look at this chunk... */ 5384 5385 if (!dev->isYaffs2 && tags.chunkDeleted) { 5386 /* YAFFS1 only... 5387 * A deleted chunk 5388 */ 5389 deleted++; 5390 dev->nFreeChunks++; 5391 /*T((" %d %d deleted\n",blk,c)); */ 5392 } else if (!tags.chunkUsed) { 5393 /* An unassigned chunk in the block 5394 * This means that either the block is empty or 5395 * this is the one being allocated from 5396 */ 5397 5398 if (c == 0) { 5399 /* We're looking at the first chunk in the block so the block is unused */ 5400 state = YAFFS_BLOCK_STATE_EMPTY; 5401 dev->nErasedBlocks++; 5402 } else { 5403 /* this is the block being allocated from */ 5404 T(YAFFS_TRACE_SCAN, 5405 (TSTR 5406 (" Allocating from %d %d" TENDSTR), 5407 blk, c)); 5408 state = YAFFS_BLOCK_STATE_ALLOCATING; 5409 dev->allocationBlock = blk; 5410 dev->allocationPage = c; 5411 dev->allocationBlockFinder = blk; 5412 /* Set it to here to encourage the allocator to go forth from here. */ 5413 5414 /* Yaffs2 sanity check: 5415 * This should be the one with the highest sequence number 5416 */ 5417 if (dev->isYaffs2 5418 && (dev->sequenceNumber != 5419 bi->sequenceNumber)) { 5420 T(YAFFS_TRACE_ALWAYS, 5421 (TSTR 5422 ("yaffs: Allocation block %d was not highest sequence id:" 5423 " block seq = %d, dev seq = %d" 5424 TENDSTR), blk,bi->sequenceNumber,dev->sequenceNumber)); 5425 } 5426 } 5427 5428 dev->nFreeChunks += (dev->nChunksPerBlock - c); 5429 } else if (tags.chunkId > 0) { 5430 /* chunkId > 0 so it is a data chunk... */ 5431 unsigned int endpos; 5432 5433 yaffs_SetChunkBit(dev, blk, c); 5434 bi->pagesInUse++; 5435 5436 in = yaffs_FindOrCreateObjectByNumber(dev, 5437 tags. 5438 objectId, 5439 YAFFS_OBJECT_TYPE_FILE); 5440 /* PutChunkIntoFile checks for a clash (two data chunks with 5441 * the same chunkId). 5442 */ 5443 5444 if(!in) 5445 alloc_failed = 1; 5446 5447 if(in){ 5448 if(!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk,1)) 5449 alloc_failed = 1; 5450 } 5451 5452 endpos = 5453 (tags.chunkId - 1) * dev->nDataBytesPerChunk + 5454 tags.byteCount; 5455 if (in && 5456 in->variantType == YAFFS_OBJECT_TYPE_FILE 5457 && in->variant.fileVariant.scannedFileSize < 5458 endpos) { 5459 in->variant.fileVariant. 5460 scannedFileSize = endpos; 5461 if (!dev->useHeaderFileSize) { 5462 in->variant.fileVariant. 5463 fileSize = 5464 in->variant.fileVariant. 5465 scannedFileSize; 5466 } 5467 5468 } 5469 /* T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId)); */ 5470 } else { 5471 /* chunkId == 0, so it is an ObjectHeader. 5472 * Thus, we read in the object header and make the object 5473 */ 5474 yaffs_SetChunkBit(dev, blk, c); 5475 bi->pagesInUse++; 5476 5477 result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, 5478 chunkData, 5479 NULL); 5480 5481 oh = (yaffs_ObjectHeader *) chunkData; 5482 5483 in = yaffs_FindObjectByNumber(dev, 5484 tags.objectId); 5485 if (in && in->variantType != oh->type) { 5486 /* This should not happen, but somehow 5487 * Wev'e ended up with an objectId that has been reused but not yet 5488 * deleted, and worse still it has changed type. Delete the old object. 5489 */ 5490 5491 yaffs_DestroyObject(in); 5492 5493 in = 0; 5494 } 5495 5496 in = yaffs_FindOrCreateObjectByNumber(dev, 5497 tags. 5498 objectId, 5499 oh->type); 5500 5501 if(!in) 5502 alloc_failed = 1; 5503 5504 if (in && oh->shadowsObject > 0) { 5505 yaffs_HandleShadowedObject(dev, 5506 oh-> 5507 shadowsObject, 5508 0); 5509 } 5510 5511 if (in && in->valid) { 5512 /* We have already filled this one. We have a duplicate and need to resolve it. */ 5513 5514 unsigned existingSerial = in->serial; 5515 unsigned newSerial = tags.serialNumber; 5516 5517 if (dev->isYaffs2 || 5518 ((existingSerial + 1) & 3) == 5519 newSerial) { 5520 /* Use new one - destroy the exisiting one */ 5521 yaffs_DeleteChunk(dev, 5522 in->chunkId, 5523 1, __LINE__); 5524 in->valid = 0; 5525 } else { 5526 /* Use existing - destroy this one. */ 5527 yaffs_DeleteChunk(dev, chunk, 1, 5528 __LINE__); 5529 } 5530 } 5531 5532 if (in && !in->valid && 5533 (tags.objectId == YAFFS_OBJECTID_ROOT || 5534 tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) { 5535 /* We only load some info, don't fiddle with directory structure */ 5536 in->valid = 1; 5537 in->variantType = oh->type; 5538 5539 in->yst_mode = oh->yst_mode; 5540 #ifdef CONFIG_YAFFS_WINCE 5541 in->win_atime[0] = oh->win_atime[0]; 5542 in->win_ctime[0] = oh->win_ctime[0]; 5543 in->win_mtime[0] = oh->win_mtime[0]; 5544 in->win_atime[1] = oh->win_atime[1]; 5545 in->win_ctime[1] = oh->win_ctime[1]; 5546 in->win_mtime[1] = oh->win_mtime[1]; 5547 #else 5548 in->yst_uid = oh->yst_uid; 5549 in->yst_gid = oh->yst_gid; 5550 in->yst_atime = oh->yst_atime; 5551 in->yst_mtime = oh->yst_mtime; 5552 in->yst_ctime = oh->yst_ctime; 5553 in->yst_rdev = oh->yst_rdev; 5554 #endif 5555 in->chunkId = chunk; 5556 5557 } else if (in && !in->valid) { 5558 /* we need to load this info */ 5559 5560 in->valid = 1; 5561 in->variantType = oh->type; 5562 5563 in->yst_mode = oh->yst_mode; 5564 #ifdef CONFIG_YAFFS_WINCE 5565 in->win_atime[0] = oh->win_atime[0]; 5566 in->win_ctime[0] = oh->win_ctime[0]; 5567 in->win_mtime[0] = oh->win_mtime[0]; 5568 in->win_atime[1] = oh->win_atime[1]; 5569 in->win_ctime[1] = oh->win_ctime[1]; 5570 in->win_mtime[1] = oh->win_mtime[1]; 5571 #else 5572 in->yst_uid = oh->yst_uid; 5573 in->yst_gid = oh->yst_gid; 5574 in->yst_atime = oh->yst_atime; 5575 in->yst_mtime = oh->yst_mtime; 5576 in->yst_ctime = oh->yst_ctime; 5577 in->yst_rdev = oh->yst_rdev; 5578 #endif 5579 in->chunkId = chunk; 5580 5581 yaffs_SetObjectName(in, oh->name); 5582 in->dirty = 0; 5583 5584 /* directory stuff... 5585 * hook up to parent 5586 */ 5587 5588 parent = 5589 yaffs_FindOrCreateObjectByNumber 5590 (dev, oh->parentObjectId, 5591 YAFFS_OBJECT_TYPE_DIRECTORY); 5592 if (parent->variantType == 5593 YAFFS_OBJECT_TYPE_UNKNOWN) { 5594 /* Set up as a directory */ 5595 parent->variantType = 5596 YAFFS_OBJECT_TYPE_DIRECTORY; 5597 INIT_LIST_HEAD(&parent->variant. 5598 directoryVariant. 5599 children); 5600 } else if (parent->variantType != 5601 YAFFS_OBJECT_TYPE_DIRECTORY) 5602 { 5603 /* Hoosterman, another problem.... 5604 * We're trying to use a non-directory as a directory 5605 */ 5606 5607 T(YAFFS_TRACE_ERROR, 5608 (TSTR 5609 ("yaffs tragedy: attempting to use non-directory as" 5610 " a directory in scan. Put in lost+found." 5611 TENDSTR))); 5612 parent = dev->lostNFoundDir; 5613 } 5614 5615 yaffs_AddObjectToDirectory(parent, in); 5616 5617 if (0 && (parent == dev->deletedDir || 5618 parent == dev->unlinkedDir)) { 5619 in->deleted = 1; /* If it is unlinked at start up then it wants deleting */ 5620 dev->nDeletedFiles++; 5621 } 5622 /* Note re hardlinks. 5623 * Since we might scan a hardlink before its equivalent object is scanned 5624 * we put them all in a list. 5625 * After scanning is complete, we should have all the objects, so we run through this 5626 * list and fix up all the chains. 5627 */ 5628 5629 switch (in->variantType) { 5630 case YAFFS_OBJECT_TYPE_UNKNOWN: 5631 /* Todo got a problem */ 5632 break; 5633 case YAFFS_OBJECT_TYPE_FILE: 5634 if (dev->isYaffs2 5635 && oh->isShrink) { 5636 /* Prune back the shrunken chunks */ 5637 yaffs_PruneResizedChunks 5638 (in, oh->fileSize); 5639 /* Mark the block as having a shrinkHeader */ 5640 bi->hasShrinkHeader = 1; 5641 } 5642 5643 if (dev->useHeaderFileSize) 5644 5645 in->variant.fileVariant. 5646 fileSize = 5647 oh->fileSize; 5648 5649 break; 5650 case YAFFS_OBJECT_TYPE_HARDLINK: 5651 in->variant.hardLinkVariant. 5652 equivalentObjectId = 5653 oh->equivalentObjectId; 5654 in->hardLinks.next = 5655 (struct list_head *) 5656 hardList; 5657 hardList = in; 5658 break; 5659 case YAFFS_OBJECT_TYPE_DIRECTORY: 5660 /* Do nothing */ 5661 break; 5662 case YAFFS_OBJECT_TYPE_SPECIAL: 5663 /* Do nothing */ 5664 break; 5665 case YAFFS_OBJECT_TYPE_SYMLINK: 5666 in->variant.symLinkVariant.alias = 5667 yaffs_CloneString(oh->alias); 5668 if(!in->variant.symLinkVariant.alias) 5669 alloc_failed = 1; 5670 break; 5671 } 5672 5673 if (parent == dev->deletedDir) { 5674 yaffs_DestroyObject(in); 5675 bi->hasShrinkHeader = 1; 5676 } 5677 } 5678 } 5679 } 5680 5681 if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { 5682 /* If we got this far while scanning, then the block is fully allocated.*/ 5683 state = YAFFS_BLOCK_STATE_FULL; 5684 } 5685 5686 bi->blockState = state; 5687 5688 /* Now let's see if it was dirty */ 5689 if (bi->pagesInUse == 0 && 5690 !bi->hasShrinkHeader && 5691 bi->blockState == YAFFS_BLOCK_STATE_FULL) { 5692 yaffs_BlockBecameDirty(dev, blk); 5693 } 5694 5695 } 5696 5697 if (blockIndex) { 5698 YFREE(blockIndex); 5699 } 5700 5701 5702 /* Ok, we've done all the scanning. 5703 * Fix up the hard link chains. 5704 * We should now have scanned all the objects, now it's time to add these 5705 * hardlinks. 5706 */ 5707 5708 yaffs_HardlinkFixup(dev,hardList); 5709 5710 /* Handle the unlinked files. Since they were left in an unlinked state we should 5711 * just delete them. 5712 */ 5713 { 5714 struct list_head *i; 5715 struct list_head *n; 5716 5717 yaffs_Object *l; 5718 /* Soft delete all the unlinked files */ 5719 list_for_each_safe(i, n, 5720 &dev->unlinkedDir->variant.directoryVariant. 5721 children) { 5722 if (i) { 5723 l = list_entry(i, yaffs_Object, siblings); 5724 yaffs_DestroyObject(l); 5725 } 5726 } 5727 } 5728 5729 yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__); 5730 5731 if(alloc_failed){ 5732 return YAFFS_FAIL; 5733 } 5734 5735 T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan ends" TENDSTR))); 5736 5737 5738 return YAFFS_OK; 5739 } 5740 5741 static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in) 5742 { 5743 __u8 *chunkData; 5744 yaffs_ObjectHeader *oh; 5745 yaffs_Device *dev = in->myDev; 5746 yaffs_ExtendedTags tags; 5747 int result; 5748 int alloc_failed = 0; 5749 5750 if(!in) 5751 return; 5752 5753 #if 0 5754 T(YAFFS_TRACE_SCAN,(TSTR("details for object %d %s loaded" TENDSTR), 5755 in->objectId, 5756 in->lazyLoaded ? "not yet" : "already")); 5757 #endif 5758 5759 if(in->lazyLoaded){ 5760 in->lazyLoaded = 0; 5761 chunkData = yaffs_GetTempBuffer(dev, __LINE__); 5762 5763 result = yaffs_ReadChunkWithTagsFromNAND(dev,in->chunkId,chunkData,&tags); 5764 oh = (yaffs_ObjectHeader *) chunkData; 5765 5766 in->yst_mode = oh->yst_mode; 5767 #ifdef CONFIG_YAFFS_WINCE 5768 in->win_atime[0] = oh->win_atime[0]; 5769 in->win_ctime[0] = oh->win_ctime[0]; 5770 in->win_mtime[0] = oh->win_mtime[0]; 5771 in->win_atime[1] = oh->win_atime[1]; 5772 in->win_ctime[1] = oh->win_ctime[1]; 5773 in->win_mtime[1] = oh->win_mtime[1]; 5774 #else 5775 in->yst_uid = oh->yst_uid; 5776 in->yst_gid = oh->yst_gid; 5777 in->yst_atime = oh->yst_atime; 5778 in->yst_mtime = oh->yst_mtime; 5779 in->yst_ctime = oh->yst_ctime; 5780 in->yst_rdev = oh->yst_rdev; 5781 5782 #endif 5783 yaffs_SetObjectName(in, oh->name); 5784 5785 if(in->variantType == YAFFS_OBJECT_TYPE_SYMLINK){ 5786 in->variant.symLinkVariant.alias = 5787 yaffs_CloneString(oh->alias); 5788 if(!in->variant.symLinkVariant.alias) 5789 alloc_failed = 1; /* Not returned to caller */ 5790 } 5791 5792 yaffs_ReleaseTempBuffer(dev,chunkData, __LINE__); 5793 } 5794 } 5795 5796 static int yaffs_ScanBackwards(yaffs_Device * dev) 5797 { 5798 yaffs_ExtendedTags tags; 5799 int blk; 5800 int blockIterator; 5801 int startIterator; 5802 int endIterator; 5803 int nBlocksToScan = 0; 5804 5805 int chunk; 5806 int result; 5807 int c; 5808 int deleted; 5809 yaffs_BlockState state; 5810 yaffs_Object *hardList = NULL; 5811 yaffs_BlockInfo *bi; 5812 int sequenceNumber; 5813 yaffs_ObjectHeader *oh; 5814 yaffs_Object *in; 5815 yaffs_Object *parent; 5816 int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1; 5817 int itsUnlinked; 5818 __u8 *chunkData; 5819 5820 int fileSize; 5821 int isShrink; 5822 int foundChunksInBlock; 5823 int equivalentObjectId; 5824 int alloc_failed = 0; 5825 5826 5827 yaffs_BlockIndex *blockIndex = NULL; 5828 int altBlockIndex = 0; 5829 5830 if (!dev->isYaffs2) { 5831 T(YAFFS_TRACE_SCAN, 5832 (TSTR("yaffs_ScanBackwards is only for YAFFS2!" TENDSTR))); 5833 return YAFFS_FAIL; 5834 } 5835 5836 T(YAFFS_TRACE_SCAN, 5837 (TSTR 5838 ("yaffs_ScanBackwards starts intstartblk %d intendblk %d..." 5839 TENDSTR), dev->internalStartBlock, dev->internalEndBlock)); 5840 5841 5842 dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER; 5843 5844 blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex)); 5845 5846 if(!blockIndex) { 5847 blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex)); 5848 altBlockIndex = 1; 5849 } 5850 5851 if(!blockIndex) { 5852 T(YAFFS_TRACE_SCAN, 5853 (TSTR("yaffs_Scan() could not allocate block index!" TENDSTR))); 5854 return YAFFS_FAIL; 5855 } 5856 5857 dev->blocksInCheckpoint = 0; 5858 5859 chunkData = yaffs_GetTempBuffer(dev, __LINE__); 5860 5861 /* Scan all the blocks to determine their state */ 5862 for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) { 5863 bi = yaffs_GetBlockInfo(dev, blk); 5864 yaffs_ClearChunkBits(dev, blk); 5865 bi->pagesInUse = 0; 5866 bi->softDeletions = 0; 5867 5868 yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber); 5869 5870 bi->blockState = state; 5871 bi->sequenceNumber = sequenceNumber; 5872 5873 if(bi->sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA) 5874 bi->blockState = state = YAFFS_BLOCK_STATE_CHECKPOINT; 5875 5876 T(YAFFS_TRACE_SCAN_DEBUG, 5877 (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk, 5878 state, sequenceNumber)); 5879 5880 5881 if(state == YAFFS_BLOCK_STATE_CHECKPOINT){ 5882 dev->blocksInCheckpoint++; 5883 5884 } else if (state == YAFFS_BLOCK_STATE_DEAD) { 5885 T(YAFFS_TRACE_BAD_BLOCKS, 5886 (TSTR("block %d is bad" TENDSTR), blk)); 5887 } else if (state == YAFFS_BLOCK_STATE_EMPTY) { 5888 T(YAFFS_TRACE_SCAN_DEBUG, 5889 (TSTR("Block empty " TENDSTR))); 5890 dev->nErasedBlocks++; 5891 dev->nFreeChunks += dev->nChunksPerBlock; 5892 } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { 5893 5894 /* Determine the highest sequence number */ 5895 if (dev->isYaffs2 && 5896 sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER && 5897 sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) { 5898 5899 blockIndex[nBlocksToScan].seq = sequenceNumber; 5900 blockIndex[nBlocksToScan].block = blk; 5901 5902 nBlocksToScan++; 5903 5904 if (sequenceNumber >= dev->sequenceNumber) { 5905 dev->sequenceNumber = sequenceNumber; 5906 } 5907 } else if (dev->isYaffs2) { 5908 /* TODO: Nasty sequence number! */ 5909 T(YAFFS_TRACE_SCAN, 5910 (TSTR 5911 ("Block scanning block %d has bad sequence number %d" 5912 TENDSTR), blk, sequenceNumber)); 5913 5914 } 5915 } 5916 } 5917 5918 T(YAFFS_TRACE_SCAN, 5919 (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan)); 5920 5921 5922 5923 YYIELD(); 5924 5925 /* Sort the blocks */ 5926 #ifndef CONFIG_YAFFS_USE_OWN_SORT 5927 { 5928 /* Use qsort now. */ 5929 yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), ybicmp); 5930 } 5931 #else 5932 { 5933 /* Dungy old bubble sort... */ 5934 5935 yaffs_BlockIndex temp; 5936 int i; 5937 int j; 5938 5939 for (i = 0; i < nBlocksToScan; i++) 5940 for (j = i + 1; j < nBlocksToScan; j++) 5941 if (blockIndex[i].seq > blockIndex[j].seq) { 5942 temp = blockIndex[j]; 5943 blockIndex[j] = blockIndex[i]; 5944 blockIndex[i] = temp; 5945 } 5946 } 5947 #endif 5948 5949 YYIELD(); 5950 5951 T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR))); 5952 5953 /* Now scan the blocks looking at the data. */ 5954 startIterator = 0; 5955 endIterator = nBlocksToScan - 1; 5956 T(YAFFS_TRACE_SCAN_DEBUG, 5957 (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan)); 5958 5959 /* For each block.... backwards */ 5960 for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator; 5961 blockIterator--) { 5962 /* Cooperative multitasking! This loop can run for so 5963 long that watchdog timers expire. */ 5964 YYIELD(); 5965 5966 /* get the block to scan in the correct order */ 5967 blk = blockIndex[blockIterator].block; 5968 5969 bi = yaffs_GetBlockInfo(dev, blk); 5970 5971 5972 state = bi->blockState; 5973 5974 deleted = 0; 5975 5976 /* For each chunk in each block that needs scanning.... */ 5977 foundChunksInBlock = 0; 5978 for (c = dev->nChunksPerBlock - 1; 5979 !alloc_failed && c >= 0 && 5980 (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING || 5981 state == YAFFS_BLOCK_STATE_ALLOCATING); c--) { 5982 /* Scan backwards... 5983 * Read the tags and decide what to do 5984 */ 5985 5986 chunk = blk * dev->nChunksPerBlock + c; 5987 5988 result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL, 5989 &tags); 5990 5991 /* Let's have a good look at this chunk... */ 5992 5993 if (!tags.chunkUsed) { 5994 /* An unassigned chunk in the block. 5995 * If there are used chunks after this one, then 5996 * it is a chunk that was skipped due to failing the erased 5997 * check. Just skip it so that it can be deleted. 5998 * But, more typically, We get here when this is an unallocated 5999 * chunk and his means that either the block is empty or 6000 * this is the one being allocated from 6001 */ 6002 6003 if(foundChunksInBlock) 6004 { 6005 /* This is a chunk that was skipped due to failing the erased check */ 6006 6007 } else if (c == 0) { 6008 /* We're looking at the first chunk in the block so the block is unused */ 6009 state = YAFFS_BLOCK_STATE_EMPTY; 6010 dev->nErasedBlocks++; 6011 } else { 6012 if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING || 6013 state == YAFFS_BLOCK_STATE_ALLOCATING) { 6014 if(dev->sequenceNumber == bi->sequenceNumber) { 6015 /* this is the block being allocated from */ 6016 6017 T(YAFFS_TRACE_SCAN, 6018 (TSTR 6019 (" Allocating from %d %d" 6020 TENDSTR), blk, c)); 6021 6022 state = YAFFS_BLOCK_STATE_ALLOCATING; 6023 dev->allocationBlock = blk; 6024 dev->allocationPage = c; 6025 dev->allocationBlockFinder = blk; 6026 } 6027 else { 6028 /* This is a partially written block that is not 6029 * the current allocation block. This block must have 6030 * had a write failure, so set up for retirement. 6031 */ 6032 6033 bi->needsRetiring = 1; 6034 bi->gcPrioritise = 1; 6035 6036 T(YAFFS_TRACE_ALWAYS, 6037 (TSTR("Partially written block %d being set for retirement" TENDSTR), 6038 blk)); 6039 } 6040 6041 } 6042 6043 } 6044 6045 dev->nFreeChunks++; 6046 6047 } else if (tags.chunkId > 0) { 6048 /* chunkId > 0 so it is a data chunk... */ 6049 unsigned int endpos; 6050 __u32 chunkBase = 6051 (tags.chunkId - 1) * dev->nDataBytesPerChunk; 6052 6053 foundChunksInBlock = 1; 6054 6055 6056 yaffs_SetChunkBit(dev, blk, c); 6057 bi->pagesInUse++; 6058 6059 in = yaffs_FindOrCreateObjectByNumber(dev, 6060 tags. 6061 objectId, 6062 YAFFS_OBJECT_TYPE_FILE); 6063 if(!in){ 6064 /* Out of memory */ 6065 alloc_failed = 1; 6066 } 6067 6068 if (in && 6069 in->variantType == YAFFS_OBJECT_TYPE_FILE 6070 && chunkBase < 6071 in->variant.fileVariant.shrinkSize) { 6072 /* This has not been invalidated by a resize */ 6073 if(!yaffs_PutChunkIntoFile(in, tags.chunkId, 6074 chunk, -1)){ 6075 alloc_failed = 1; 6076 } 6077 6078 /* File size is calculated by looking at the data chunks if we have not 6079 * seen an object header yet. Stop this practice once we find an object header. 6080 */ 6081 endpos = 6082 (tags.chunkId - 6083 1) * dev->nDataBytesPerChunk + 6084 tags.byteCount; 6085 6086 if (!in->valid && /* have not got an object header yet */ 6087 in->variant.fileVariant. 6088 scannedFileSize < endpos) { 6089 in->variant.fileVariant. 6090 scannedFileSize = endpos; 6091 in->variant.fileVariant. 6092 fileSize = 6093 in->variant.fileVariant. 6094 scannedFileSize; 6095 } 6096 6097 } else if(in) { 6098 /* This chunk has been invalidated by a resize, so delete */ 6099 yaffs_DeleteChunk(dev, chunk, 1, __LINE__); 6100 6101 } 6102 } else { 6103 /* chunkId == 0, so it is an ObjectHeader. 6104 * Thus, we read in the object header and make the object 6105 */ 6106 foundChunksInBlock = 1; 6107 6108 yaffs_SetChunkBit(dev, blk, c); 6109 bi->pagesInUse++; 6110 6111 oh = NULL; 6112 in = NULL; 6113 6114 if (tags.extraHeaderInfoAvailable) { 6115 in = yaffs_FindOrCreateObjectByNumber 6116 (dev, tags.objectId, 6117 tags.extraObjectType); 6118 } 6119 6120 if (!in || 6121 #ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD 6122 !in->valid || 6123 #endif 6124 tags.extraShadows || 6125 (!in->valid && 6126 (tags.objectId == YAFFS_OBJECTID_ROOT || 6127 tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) 6128 ) { 6129 6130 /* If we don't have valid info then we need to read the chunk 6131 * TODO In future we can probably defer reading the chunk and 6132 * living with invalid data until needed. 6133 */ 6134 6135 result = yaffs_ReadChunkWithTagsFromNAND(dev, 6136 chunk, 6137 chunkData, 6138 NULL); 6139 6140 oh = (yaffs_ObjectHeader *) chunkData; 6141 6142 if (!in) 6143 in = yaffs_FindOrCreateObjectByNumber(dev, tags.objectId, oh->type); 6144 6145 } 6146 6147 if (!in) { 6148 /* TODO Hoosterman we have a problem! */ 6149 T(YAFFS_TRACE_ERROR, 6150 (TSTR 6151 ("yaffs tragedy: Could not make object for object %d " 6152 "at chunk %d during scan" 6153 TENDSTR), tags.objectId, chunk)); 6154 6155 } 6156 6157 if (in->valid) { 6158 /* We have already filled this one. 6159 * We have a duplicate that will be discarded, but 6160 * we first have to suck out resize info if it is a file. 6161 */ 6162 6163 if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) && 6164 ((oh && 6165 oh-> type == YAFFS_OBJECT_TYPE_FILE)|| 6166 (tags.extraHeaderInfoAvailable && 6167 tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE)) 6168 ) { 6169 __u32 thisSize = 6170 (oh) ? oh->fileSize : tags. 6171 extraFileLength; 6172 __u32 parentObjectId = 6173 (oh) ? oh-> 6174 parentObjectId : tags. 6175 extraParentObjectId; 6176 unsigned isShrink = 6177 (oh) ? oh->isShrink : tags. 6178 extraIsShrinkHeader; 6179 6180 /* If it is deleted (unlinked at start also means deleted) 6181 * we treat the file size as being zeroed at this point. 6182 */ 6183 if (parentObjectId == 6184 YAFFS_OBJECTID_DELETED 6185 || parentObjectId == 6186 YAFFS_OBJECTID_UNLINKED) { 6187 thisSize = 0; 6188 isShrink = 1; 6189 } 6190 6191 if (isShrink && 6192 in->variant.fileVariant. 6193 shrinkSize > thisSize) { 6194 in->variant.fileVariant. 6195 shrinkSize = 6196 thisSize; 6197 } 6198 6199 if (isShrink) { 6200 bi->hasShrinkHeader = 1; 6201 } 6202 6203 } 6204 /* Use existing - destroy this one. */ 6205 yaffs_DeleteChunk(dev, chunk, 1, __LINE__); 6206 6207 } 6208 6209 if (!in->valid && 6210 (tags.objectId == YAFFS_OBJECTID_ROOT || 6211 tags.objectId == 6212 YAFFS_OBJECTID_LOSTNFOUND)) { 6213 /* We only load some info, don't fiddle with directory structure */ 6214 in->valid = 1; 6215 6216 if(oh) { 6217 in->variantType = oh->type; 6218 6219 in->yst_mode = oh->yst_mode; 6220 #ifdef CONFIG_YAFFS_WINCE 6221 in->win_atime[0] = oh->win_atime[0]; 6222 in->win_ctime[0] = oh->win_ctime[0]; 6223 in->win_mtime[0] = oh->win_mtime[0]; 6224 in->win_atime[1] = oh->win_atime[1]; 6225 in->win_ctime[1] = oh->win_ctime[1]; 6226 in->win_mtime[1] = oh->win_mtime[1]; 6227 #else 6228 in->yst_uid = oh->yst_uid; 6229 in->yst_gid = oh->yst_gid; 6230 in->yst_atime = oh->yst_atime; 6231 in->yst_mtime = oh->yst_mtime; 6232 in->yst_ctime = oh->yst_ctime; 6233 in->yst_rdev = oh->yst_rdev; 6234 6235 #endif 6236 } else { 6237 in->variantType = tags.extraObjectType; 6238 in->lazyLoaded = 1; 6239 } 6240 6241 in->chunkId = chunk; 6242 6243 } else if (!in->valid) { 6244 /* we need to load this info */ 6245 6246 in->valid = 1; 6247 in->chunkId = chunk; 6248 6249 if(oh) { 6250 in->variantType = oh->type; 6251 6252 in->yst_mode = oh->yst_mode; 6253 #ifdef CONFIG_YAFFS_WINCE 6254 in->win_atime[0] = oh->win_atime[0]; 6255 in->win_ctime[0] = oh->win_ctime[0]; 6256 in->win_mtime[0] = oh->win_mtime[0]; 6257 in->win_atime[1] = oh->win_atime[1]; 6258 in->win_ctime[1] = oh->win_ctime[1]; 6259 in->win_mtime[1] = oh->win_mtime[1]; 6260 #else 6261 in->yst_uid = oh->yst_uid; 6262 in->yst_gid = oh->yst_gid; 6263 in->yst_atime = oh->yst_atime; 6264 in->yst_mtime = oh->yst_mtime; 6265 in->yst_ctime = oh->yst_ctime; 6266 in->yst_rdev = oh->yst_rdev; 6267 #endif 6268 6269 if (oh->shadowsObject > 0) 6270 yaffs_HandleShadowedObject(dev, 6271 oh-> 6272 shadowsObject, 6273 1); 6274 6275 6276 yaffs_SetObjectName(in, oh->name); 6277 parent = 6278 yaffs_FindOrCreateObjectByNumber 6279 (dev, oh->parentObjectId, 6280 YAFFS_OBJECT_TYPE_DIRECTORY); 6281 6282 fileSize = oh->fileSize; 6283 isShrink = oh->isShrink; 6284 equivalentObjectId = oh->equivalentObjectId; 6285 6286 } 6287 else { 6288 in->variantType = tags.extraObjectType; 6289 parent = 6290 yaffs_FindOrCreateObjectByNumber 6291 (dev, tags.extraParentObjectId, 6292 YAFFS_OBJECT_TYPE_DIRECTORY); 6293 fileSize = tags.extraFileLength; 6294 isShrink = tags.extraIsShrinkHeader; 6295 equivalentObjectId = tags.extraEquivalentObjectId; 6296 in->lazyLoaded = 1; 6297 6298 } 6299 in->dirty = 0; 6300 6301 /* directory stuff... 6302 * hook up to parent 6303 */ 6304 6305 if (parent->variantType == 6306 YAFFS_OBJECT_TYPE_UNKNOWN) { 6307 /* Set up as a directory */ 6308 parent->variantType = 6309 YAFFS_OBJECT_TYPE_DIRECTORY; 6310 INIT_LIST_HEAD(&parent->variant. 6311 directoryVariant. 6312 children); 6313 } else if (parent->variantType != 6314 YAFFS_OBJECT_TYPE_DIRECTORY) 6315 { 6316 /* Hoosterman, another problem.... 6317 * We're trying to use a non-directory as a directory 6318 */ 6319 6320 T(YAFFS_TRACE_ERROR, 6321 (TSTR 6322 ("yaffs tragedy: attempting to use non-directory as" 6323 " a directory in scan. Put in lost+found." 6324 TENDSTR))); 6325 parent = dev->lostNFoundDir; 6326 } 6327 6328 yaffs_AddObjectToDirectory(parent, in); 6329 6330 itsUnlinked = (parent == dev->deletedDir) || 6331 (parent == dev->unlinkedDir); 6332 6333 if (isShrink) { 6334 /* Mark the block as having a shrinkHeader */ 6335 bi->hasShrinkHeader = 1; 6336 } 6337 6338 /* Note re hardlinks. 6339 * Since we might scan a hardlink before its equivalent object is scanned 6340 * we put them all in a list. 6341 * After scanning is complete, we should have all the objects, so we run 6342 * through this list and fix up all the chains. 6343 */ 6344 6345 switch (in->variantType) { 6346 case YAFFS_OBJECT_TYPE_UNKNOWN: 6347 /* Todo got a problem */ 6348 break; 6349 case YAFFS_OBJECT_TYPE_FILE: 6350 6351 if (in->variant.fileVariant. 6352 scannedFileSize < fileSize) { 6353 /* This covers the case where the file size is greater 6354 * than where the data is 6355 * This will happen if the file is resized to be larger 6356 * than its current data extents. 6357 */ 6358 in->variant.fileVariant.fileSize = fileSize; 6359 in->variant.fileVariant.scannedFileSize = 6360 in->variant.fileVariant.fileSize; 6361 } 6362 6363 if (isShrink && 6364 in->variant.fileVariant.shrinkSize > fileSize) { 6365 in->variant.fileVariant.shrinkSize = fileSize; 6366 } 6367 6368 break; 6369 case YAFFS_OBJECT_TYPE_HARDLINK: 6370 if(!itsUnlinked) { 6371 in->variant.hardLinkVariant.equivalentObjectId = 6372 equivalentObjectId; 6373 in->hardLinks.next = 6374 (struct list_head *) hardList; 6375 hardList = in; 6376 } 6377 break; 6378 case YAFFS_OBJECT_TYPE_DIRECTORY: 6379 /* Do nothing */ 6380 break; 6381 case YAFFS_OBJECT_TYPE_SPECIAL: 6382 /* Do nothing */ 6383 break; 6384 case YAFFS_OBJECT_TYPE_SYMLINK: 6385 if(oh){ 6386 in->variant.symLinkVariant.alias = 6387 yaffs_CloneString(oh-> 6388 alias); 6389 if(!in->variant.symLinkVariant.alias) 6390 alloc_failed = 1; 6391 } 6392 break; 6393 } 6394 6395 } 6396 6397 } 6398 6399 } /* End of scanning for each chunk */ 6400 6401 if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { 6402 /* If we got this far while scanning, then the block is fully allocated. */ 6403 state = YAFFS_BLOCK_STATE_FULL; 6404 } 6405 6406 bi->blockState = state; 6407 6408 /* Now let's see if it was dirty */ 6409 if (bi->pagesInUse == 0 && 6410 !bi->hasShrinkHeader && 6411 bi->blockState == YAFFS_BLOCK_STATE_FULL) { 6412 yaffs_BlockBecameDirty(dev, blk); 6413 } 6414 6415 } 6416 6417 if (altBlockIndex) 6418 YFREE_ALT(blockIndex); 6419 else 6420 YFREE(blockIndex); 6421 6422 /* Ok, we've done all the scanning. 6423 * Fix up the hard link chains. 6424 * We should now have scanned all the objects, now it's time to add these 6425 * hardlinks. 6426 */ 6427 yaffs_HardlinkFixup(dev,hardList); 6428 6429 6430 /* 6431 * Sort out state of unlinked and deleted objects. 6432 */ 6433 { 6434 struct list_head *i; 6435 struct list_head *n; 6436 6437 yaffs_Object *l; 6438 6439 /* Soft delete all the unlinked files */ 6440 list_for_each_safe(i, n, 6441 &dev->unlinkedDir->variant.directoryVariant. 6442 children) { 6443 if (i) { 6444 l = list_entry(i, yaffs_Object, siblings); 6445 yaffs_DestroyObject(l); 6446 } 6447 } 6448 6449 /* Soft delete all the deletedDir files */ 6450 list_for_each_safe(i, n, 6451 &dev->deletedDir->variant.directoryVariant. 6452 children) { 6453 if (i) { 6454 l = list_entry(i, yaffs_Object, siblings); 6455 yaffs_DestroyObject(l); 6456 6457 } 6458 } 6459 } 6460 6461 yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__); 6462 6463 if(alloc_failed){ 6464 return YAFFS_FAIL; 6465 } 6466 6467 T(YAFFS_TRACE_SCAN, (TSTR("yaffs_ScanBackwards ends" TENDSTR))); 6468 6469 return YAFFS_OK; 6470 } 6471 6472 /*------------------------------ Directory Functions ----------------------------- */ 6473 6474 static void yaffs_RemoveObjectFromDirectory(yaffs_Object * obj) 6475 { 6476 yaffs_Device *dev = obj->myDev; 6477 6478 if(dev && dev->removeObjectCallback) 6479 dev->removeObjectCallback(obj); 6480 6481 list_del_init(&obj->siblings); 6482 obj->parent = NULL; 6483 } 6484 6485 6486 static void yaffs_AddObjectToDirectory(yaffs_Object * directory, 6487 yaffs_Object * obj) 6488 { 6489 6490 if (!directory) { 6491 T(YAFFS_TRACE_ALWAYS, 6492 (TSTR 6493 ("tragedy: Trying to add an object to a null pointer directory" 6494 TENDSTR))); 6495 YBUG(); 6496 } 6497 if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { 6498 T(YAFFS_TRACE_ALWAYS, 6499 (TSTR 6500 ("tragedy: Trying to add an object to a non-directory" 6501 TENDSTR))); 6502 YBUG(); 6503 } 6504 6505 if (obj->siblings.prev == NULL) { 6506 /* Not initialised */ 6507 INIT_LIST_HEAD(&obj->siblings); 6508 6509 } else if (!list_empty(&obj->siblings)) { 6510 /* If it is holed up somewhere else, un hook it */ 6511 yaffs_RemoveObjectFromDirectory(obj); 6512 } 6513 /* Now add it */ 6514 list_add(&obj->siblings, &directory->variant.directoryVariant.children); 6515 obj->parent = directory; 6516 6517 if (directory == obj->myDev->unlinkedDir 6518 || directory == obj->myDev->deletedDir) { 6519 obj->unlinked = 1; 6520 obj->myDev->nUnlinkedFiles++; 6521 obj->renameAllowed = 0; 6522 } 6523 } 6524 6525 yaffs_Object *yaffs_FindObjectByName(yaffs_Object * directory, 6526 const YCHAR * name) 6527 { 6528 int sum; 6529 6530 struct list_head *i; 6531 YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1]; 6532 6533 yaffs_Object *l; 6534 6535 if (!name) { 6536 return NULL; 6537 } 6538 6539 if (!directory) { 6540 T(YAFFS_TRACE_ALWAYS, 6541 (TSTR 6542 ("tragedy: yaffs_FindObjectByName: null pointer directory" 6543 TENDSTR))); 6544 YBUG(); 6545 } 6546 if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { 6547 T(YAFFS_TRACE_ALWAYS, 6548 (TSTR 6549 ("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR))); 6550 YBUG(); 6551 } 6552 6553 sum = yaffs_CalcNameSum(name); 6554 6555 list_for_each(i, &directory->variant.directoryVariant.children) { 6556 if (i) { 6557 l = list_entry(i, yaffs_Object, siblings); 6558 6559 yaffs_CheckObjectDetailsLoaded(l); 6560 6561 /* Special case for lost-n-found */ 6562 if (l->objectId == YAFFS_OBJECTID_LOSTNFOUND) { 6563 if (yaffs_strcmp(name, YAFFS_LOSTNFOUND_NAME) == 0) { 6564 return l; 6565 } 6566 } else if (yaffs_SumCompare(l->sum, sum) || l->chunkId <= 0) 6567 { 6568 /* LostnFound cunk called Objxxx 6569 * Do a real check 6570 */ 6571 yaffs_GetObjectName(l, buffer, 6572 YAFFS_MAX_NAME_LENGTH); 6573 if (yaffs_strncmp(name, buffer,YAFFS_MAX_NAME_LENGTH) == 0) { 6574 return l; 6575 } 6576 6577 } 6578 } 6579 } 6580 6581 return NULL; 6582 } 6583 6584 6585 #if 0 6586 int yaffs_ApplyToDirectoryChildren(yaffs_Object * theDir, 6587 int (*fn) (yaffs_Object *)) 6588 { 6589 struct list_head *i; 6590 yaffs_Object *l; 6591 6592 if (!theDir) { 6593 T(YAFFS_TRACE_ALWAYS, 6594 (TSTR 6595 ("tragedy: yaffs_FindObjectByName: null pointer directory" 6596 TENDSTR))); 6597 YBUG(); 6598 } 6599 if (theDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { 6600 T(YAFFS_TRACE_ALWAYS, 6601 (TSTR 6602 ("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR))); 6603 YBUG(); 6604 } 6605 6606 list_for_each(i, &theDir->variant.directoryVariant.children) { 6607 if (i) { 6608 l = list_entry(i, yaffs_Object, siblings); 6609 if (l && !fn(l)) { 6610 return YAFFS_FAIL; 6611 } 6612 } 6613 } 6614 6615 return YAFFS_OK; 6616 6617 } 6618 #endif 6619 6620 /* GetEquivalentObject dereferences any hard links to get to the 6621 * actual object. 6622 */ 6623 6624 yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object * obj) 6625 { 6626 if (obj && obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) { 6627 /* We want the object id of the equivalent object, not this one */ 6628 obj = obj->variant.hardLinkVariant.equivalentObject; 6629 yaffs_CheckObjectDetailsLoaded(obj); 6630 } 6631 return obj; 6632 6633 } 6634 6635 int yaffs_GetObjectName(yaffs_Object * obj, YCHAR * name, int buffSize) 6636 { 6637 memset(name, 0, buffSize * sizeof(YCHAR)); 6638 6639 yaffs_CheckObjectDetailsLoaded(obj); 6640 6641 if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) { 6642 yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1); 6643 } else if (obj->chunkId <= 0) { 6644 YCHAR locName[20]; 6645 /* make up a name */ 6646 yaffs_sprintf(locName, _Y("%s%d"), YAFFS_LOSTNFOUND_PREFIX, 6647 obj->objectId); 6648 yaffs_strncpy(name, locName, buffSize - 1); 6649 6650 } 6651 #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM 6652 else if (obj->shortName[0]) { 6653 yaffs_strcpy(name, obj->shortName); 6654 } 6655 #endif 6656 else { 6657 int result; 6658 __u8 *buffer = yaffs_GetTempBuffer(obj->myDev, __LINE__); 6659 6660 yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *) buffer; 6661 6662 memset(buffer, 0, obj->myDev->nDataBytesPerChunk); 6663 6664 if (obj->chunkId >= 0) { 6665 result = yaffs_ReadChunkWithTagsFromNAND(obj->myDev, 6666 obj->chunkId, buffer, 6667 NULL); 6668 } 6669 yaffs_strncpy(name, oh->name, buffSize - 1); 6670 6671 yaffs_ReleaseTempBuffer(obj->myDev, buffer, __LINE__); 6672 } 6673 6674 return yaffs_strlen(name); 6675 } 6676 6677 int yaffs_GetObjectFileLength(yaffs_Object * obj) 6678 { 6679 6680 /* Dereference any hard linking */ 6681 obj = yaffs_GetEquivalentObject(obj); 6682 6683 if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) { 6684 return obj->variant.fileVariant.fileSize; 6685 } 6686 if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) { 6687 return yaffs_strlen(obj->variant.symLinkVariant.alias); 6688 } else { 6689 /* Only a directory should drop through to here */ 6690 return obj->myDev->nDataBytesPerChunk; 6691 } 6692 } 6693 6694 int yaffs_GetObjectLinkCount(yaffs_Object * obj) 6695 { 6696 int count = 0; 6697 struct list_head *i; 6698 6699 if (!obj->unlinked) { 6700 count++; /* the object itself */ 6701 } 6702 list_for_each(i, &obj->hardLinks) { 6703 count++; /* add the hard links; */ 6704 } 6705 return count; 6706 6707 } 6708 6709 int yaffs_GetObjectInode(yaffs_Object * obj) 6710 { 6711 obj = yaffs_GetEquivalentObject(obj); 6712 6713 return obj->objectId; 6714 } 6715 6716 unsigned yaffs_GetObjectType(yaffs_Object * obj) 6717 { 6718 obj = yaffs_GetEquivalentObject(obj); 6719 6720 switch (obj->variantType) { 6721 case YAFFS_OBJECT_TYPE_FILE: 6722 return DT_REG; 6723 break; 6724 case YAFFS_OBJECT_TYPE_DIRECTORY: 6725 return DT_DIR; 6726 break; 6727 case YAFFS_OBJECT_TYPE_SYMLINK: 6728 return DT_LNK; 6729 break; 6730 case YAFFS_OBJECT_TYPE_HARDLINK: 6731 return DT_REG; 6732 break; 6733 case YAFFS_OBJECT_TYPE_SPECIAL: 6734 if (S_ISFIFO(obj->yst_mode)) 6735 return DT_FIFO; 6736 if (S_ISCHR(obj->yst_mode)) 6737 return DT_CHR; 6738 if (S_ISBLK(obj->yst_mode)) 6739 return DT_BLK; 6740 if (S_ISSOCK(obj->yst_mode)) 6741 return DT_SOCK; 6742 default: 6743 return DT_REG; 6744 break; 6745 } 6746 } 6747 6748 YCHAR *yaffs_GetSymlinkAlias(yaffs_Object * obj) 6749 { 6750 obj = yaffs_GetEquivalentObject(obj); 6751 if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) { 6752 return yaffs_CloneString(obj->variant.symLinkVariant.alias); 6753 } else { 6754 return yaffs_CloneString(_Y("")); 6755 } 6756 } 6757 6758 #ifndef CONFIG_YAFFS_WINCE 6759 6760 int yaffs_SetAttributes(yaffs_Object * obj, struct iattr *attr) 6761 { 6762 unsigned int valid = attr->ia_valid; 6763 6764 if (valid & ATTR_MODE) 6765 obj->yst_mode = attr->ia_mode; 6766 if (valid & ATTR_UID) 6767 obj->yst_uid = attr->ia_uid; 6768 if (valid & ATTR_GID) 6769 obj->yst_gid = attr->ia_gid; 6770 6771 if (valid & ATTR_ATIME) 6772 obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime); 6773 if (valid & ATTR_CTIME) 6774 obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime); 6775 if (valid & ATTR_MTIME) 6776 obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime); 6777 6778 if (valid & ATTR_SIZE) 6779 yaffs_ResizeFile(obj, attr->ia_size); 6780 6781 yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0); 6782 6783 return YAFFS_OK; 6784 6785 } 6786 int yaffs_GetAttributes(yaffs_Object * obj, struct iattr *attr) 6787 { 6788 unsigned int valid = 0; 6789 6790 attr->ia_mode = obj->yst_mode; 6791 valid |= ATTR_MODE; 6792 attr->ia_uid = obj->yst_uid; 6793 valid |= ATTR_UID; 6794 attr->ia_gid = obj->yst_gid; 6795 valid |= ATTR_GID; 6796 6797 Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime; 6798 valid |= ATTR_ATIME; 6799 Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime; 6800 valid |= ATTR_CTIME; 6801 Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime; 6802 valid |= ATTR_MTIME; 6803 6804 attr->ia_size = yaffs_GetFileSize(obj); 6805 valid |= ATTR_SIZE; 6806 6807 attr->ia_valid = valid; 6808 6809 return YAFFS_OK; 6810 6811 } 6812 6813 #endif 6814 6815 #if 0 6816 int yaffs_DumpObject(yaffs_Object * obj) 6817 { 6818 YCHAR name[257]; 6819 6820 yaffs_GetObjectName(obj, name, 256); 6821 6822 T(YAFFS_TRACE_ALWAYS, 6823 (TSTR 6824 ("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d" 6825 " chunk %d type %d size %d\n" 6826 TENDSTR), obj->objectId, yaffs_GetObjectInode(obj), name, 6827 obj->dirty, obj->valid, obj->serial, obj->sum, obj->chunkId, 6828 yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj))); 6829 6830 return YAFFS_OK; 6831 } 6832 #endif 6833 6834 /*---------------------------- Initialisation code -------------------------------------- */ 6835 6836 static int yaffs_CheckDevFunctions(const yaffs_Device * dev) 6837 { 6838 6839 /* Common functions, gotta have */ 6840 if (!dev->eraseBlockInNAND || !dev->initialiseNAND) 6841 return 0; 6842 6843 #ifdef CONFIG_YAFFS_YAFFS2 6844 6845 /* Can use the "with tags" style interface for yaffs1 or yaffs2 */ 6846 if (dev->writeChunkWithTagsToNAND && 6847 dev->readChunkWithTagsFromNAND && 6848 !dev->writeChunkToNAND && 6849 !dev->readChunkFromNAND && 6850 dev->markNANDBlockBad && dev->queryNANDBlock) 6851 return 1; 6852 #endif 6853 6854 /* Can use the "spare" style interface for yaffs1 */ 6855 if (!dev->isYaffs2 && 6856 !dev->writeChunkWithTagsToNAND && 6857 !dev->readChunkWithTagsFromNAND && 6858 dev->writeChunkToNAND && 6859 dev->readChunkFromNAND && 6860 !dev->markNANDBlockBad && !dev->queryNANDBlock) 6861 return 1; 6862 6863 return 0; /* bad */ 6864 } 6865 6866 6867 static int yaffs_CreateInitialDirectories(yaffs_Device *dev) 6868 { 6869 /* Initialise the unlinked, deleted, root and lost and found directories */ 6870 6871 dev->lostNFoundDir = dev->rootDir = NULL; 6872 dev->unlinkedDir = dev->deletedDir = NULL; 6873 6874 dev->unlinkedDir = 6875 yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR); 6876 6877 dev->deletedDir = 6878 yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_DELETED, S_IFDIR); 6879 6880 dev->rootDir = 6881 yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_ROOT, 6882 YAFFS_ROOT_MODE | S_IFDIR); 6883 dev->lostNFoundDir = 6884 yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_LOSTNFOUND, 6885 YAFFS_LOSTNFOUND_MODE | S_IFDIR); 6886 6887 if(dev->lostNFoundDir && dev->rootDir && dev->unlinkedDir && dev->deletedDir){ 6888 yaffs_AddObjectToDirectory(dev->rootDir, dev->lostNFoundDir); 6889 return YAFFS_OK; 6890 } 6891 6892 return YAFFS_FAIL; 6893 } 6894 6895 int yaffs_GutsInitialise(yaffs_Device * dev) 6896 { 6897 int init_failed = 0; 6898 unsigned x; 6899 int bits; 6900 6901 T(YAFFS_TRACE_TRACING, (TSTR("yaffs: yaffs_GutsInitialise()" TENDSTR))); 6902 6903 /* Check stuff that must be set */ 6904 6905 if (!dev) { 6906 T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Need a device" TENDSTR))); 6907 return YAFFS_FAIL; 6908 } 6909 6910 dev->internalStartBlock = dev->startBlock; 6911 dev->internalEndBlock = dev->endBlock; 6912 dev->blockOffset = 0; 6913 dev->chunkOffset = 0; 6914 dev->nFreeChunks = 0; 6915 6916 if (dev->startBlock == 0) { 6917 dev->internalStartBlock = dev->startBlock + 1; 6918 dev->internalEndBlock = dev->endBlock + 1; 6919 dev->blockOffset = 1; 6920 dev->chunkOffset = dev->nChunksPerBlock; 6921 } 6922 6923 /* Check geometry parameters. */ 6924 6925 if ((dev->isYaffs2 && dev->nDataBytesPerChunk < 1024) || 6926 (!dev->isYaffs2 && dev->nDataBytesPerChunk != 512) || 6927 dev->nChunksPerBlock < 2 || 6928 dev->nReservedBlocks < 2 || 6929 dev->internalStartBlock <= 0 || 6930 dev->internalEndBlock <= 0 || 6931 dev->internalEndBlock <= (dev->internalStartBlock + dev->nReservedBlocks + 2) // otherwise it is too small 6932 ) { 6933 T(YAFFS_TRACE_ALWAYS, 6934 (TSTR 6935 ("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s " 6936 TENDSTR), dev->nDataBytesPerChunk, dev->isYaffs2 ? "2" : "")); 6937 return YAFFS_FAIL; 6938 } 6939 6940 if (yaffs_InitialiseNAND(dev) != YAFFS_OK) { 6941 T(YAFFS_TRACE_ALWAYS, 6942 (TSTR("yaffs: InitialiseNAND failed" TENDSTR))); 6943 return YAFFS_FAIL; 6944 } 6945 6946 /* Got the right mix of functions? */ 6947 if (!yaffs_CheckDevFunctions(dev)) { 6948 /* Function missing */ 6949 T(YAFFS_TRACE_ALWAYS, 6950 (TSTR 6951 ("yaffs: device function(s) missing or wrong\n" TENDSTR))); 6952 6953 return YAFFS_FAIL; 6954 } 6955 6956 /* This is really a compilation check. */ 6957 if (!yaffs_CheckStructures()) { 6958 T(YAFFS_TRACE_ALWAYS, 6959 (TSTR("yaffs_CheckStructures failed\n" TENDSTR))); 6960 return YAFFS_FAIL; 6961 } 6962 6963 if (dev->isMounted) { 6964 T(YAFFS_TRACE_ALWAYS, 6965 (TSTR("yaffs: device already mounted\n" TENDSTR))); 6966 return YAFFS_FAIL; 6967 } 6968 6969 /* Finished with most checks. One or two more checks happen later on too. */ 6970 6971 dev->isMounted = 1; 6972 6973 6974 6975 /* OK now calculate a few things for the device */ 6976 6977 /* 6978 * Calculate all the chunk size manipulation numbers: 6979 */ 6980 /* Start off assuming it is a power of 2 */ 6981 dev->chunkShift = ShiftDiv(dev->nDataBytesPerChunk); 6982 dev->chunkMask = (1<<dev->chunkShift) - 1; 6983 6984 if(dev->nDataBytesPerChunk == (dev->chunkMask + 1)){ 6985 /* Yes it is a power of 2, disable crumbs */ 6986 dev->crumbMask = 0; 6987 dev->crumbShift = 0; 6988 dev->crumbsPerChunk = 0; 6989 } else { 6990 /* Not a power of 2, use crumbs instead */ 6991 dev->crumbShift = ShiftDiv(sizeof(yaffs_PackedTags2TagsPart)); 6992 dev->crumbMask = (1<<dev->crumbShift)-1; 6993 dev->crumbsPerChunk = dev->nDataBytesPerChunk/(1 << dev->crumbShift); 6994 dev->chunkShift = 0; 6995 dev->chunkMask = 0; 6996 } 6997 6998 6999 /* 7000 * Calculate chunkGroupBits. 7001 * We need to find the next power of 2 > than internalEndBlock 7002 */ 7003 7004 x = dev->nChunksPerBlock * (dev->internalEndBlock + 1); 7005 7006 bits = ShiftsGE(x); 7007 7008 /* Set up tnode width if wide tnodes are enabled. */ 7009 if(!dev->wideTnodesDisabled){ 7010 /* bits must be even so that we end up with 32-bit words */ 7011 if(bits & 1) 7012 bits++; 7013 if(bits < 16) 7014 dev->tnodeWidth = 16; 7015 else 7016 dev->tnodeWidth = bits; 7017 } 7018 else 7019 dev->tnodeWidth = 16; 7020 7021 dev->tnodeMask = (1<<dev->tnodeWidth)-1; 7022 7023 /* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled), 7024 * so if the bitwidth of the 7025 * chunk range we're using is greater than 16 we need 7026 * to figure out chunk shift and chunkGroupSize 7027 */ 7028 7029 if (bits <= dev->tnodeWidth) 7030 dev->chunkGroupBits = 0; 7031 else 7032 dev->chunkGroupBits = bits - dev->tnodeWidth; 7033 7034 7035 dev->chunkGroupSize = 1 << dev->chunkGroupBits; 7036 7037 if (dev->nChunksPerBlock < dev->chunkGroupSize) { 7038 /* We have a problem because the soft delete won't work if 7039 * the chunk group size > chunks per block. 7040 * This can be remedied by using larger "virtual blocks". 7041 */ 7042 T(YAFFS_TRACE_ALWAYS, 7043 (TSTR("yaffs: chunk group too large\n" TENDSTR))); 7044 7045 return YAFFS_FAIL; 7046 } 7047 7048 /* OK, we've finished verifying the device, lets continue with initialisation */ 7049 7050 /* More device initialisation */ 7051 dev->garbageCollections = 0; 7052 dev->passiveGarbageCollections = 0; 7053 dev->currentDirtyChecker = 0; 7054 dev->bufferedBlock = -1; 7055 dev->doingBufferedBlockRewrite = 0; 7056 dev->nDeletedFiles = 0; 7057 dev->nBackgroundDeletions = 0; 7058 dev->nUnlinkedFiles = 0; 7059 dev->eccFixed = 0; 7060 dev->eccUnfixed = 0; 7061 dev->tagsEccFixed = 0; 7062 dev->tagsEccUnfixed = 0; 7063 dev->nErasureFailures = 0; 7064 dev->nErasedBlocks = 0; 7065 dev->isDoingGC = 0; 7066 dev->hasPendingPrioritisedGCs = 1; /* Assume the worst for now, will get fixed on first GC */ 7067 7068 /* Initialise temporary buffers and caches. */ 7069 if(!yaffs_InitialiseTempBuffers(dev)) 7070 init_failed = 1; 7071 7072 dev->srCache = NULL; 7073 dev->gcCleanupList = NULL; 7074 7075 7076 if (!init_failed && 7077 dev->nShortOpCaches > 0) { 7078 int i; 7079 __u8 *buf; 7080 int srCacheBytes = dev->nShortOpCaches * sizeof(yaffs_ChunkCache); 7081 7082 if (dev->nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES) { 7083 dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES; 7084 } 7085 7086 dev->srCache = YMALLOC(srCacheBytes); 7087 buf = (__u8 *)dev->srCache; 7088 7089 if(dev->srCache) 7090 memset(dev->srCache,0,srCacheBytes); 7091 7092 for (i = 0; i < dev->nShortOpCaches && buf; i++) { 7093 dev->srCache[i].object = NULL; 7094 dev->srCache[i].lastUse = 0; 7095 dev->srCache[i].dirty = 0; 7096 dev->srCache[i].data = buf = YMALLOC_DMA(dev->nDataBytesPerChunk); 7097 } 7098 if(!buf) 7099 init_failed = 1; 7100 7101 dev->srLastUse = 0; 7102 } 7103 7104 dev->cacheHits = 0; 7105 7106 if(!init_failed){ 7107 dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32)); 7108 if(!dev->gcCleanupList) 7109 init_failed = 1; 7110 } 7111 7112 if (dev->isYaffs2) { 7113 dev->useHeaderFileSize = 1; 7114 } 7115 if(!init_failed && !yaffs_InitialiseBlocks(dev)) 7116 init_failed = 1; 7117 7118 yaffs_InitialiseTnodes(dev); 7119 yaffs_InitialiseObjects(dev); 7120 7121 if(!init_failed && !yaffs_CreateInitialDirectories(dev)) 7122 init_failed = 1; 7123 7124 7125 if(!init_failed){ 7126 /* Now scan the flash. */ 7127 if (dev->isYaffs2) { 7128 if(yaffs_CheckpointRestore(dev)) { 7129 T(YAFFS_TRACE_ALWAYS, 7130 (TSTR("yaffs: restored from checkpoint" TENDSTR))); 7131 } else { 7132 7133 /* Clean up the mess caused by an aborted checkpoint load 7134 * and scan backwards. 7135 */ 7136 yaffs_DeinitialiseBlocks(dev); 7137 yaffs_DeinitialiseTnodes(dev); 7138 yaffs_DeinitialiseObjects(dev); 7139 7140 7141 dev->nErasedBlocks = 0; 7142 dev->nFreeChunks = 0; 7143 dev->allocationBlock = -1; 7144 dev->allocationPage = -1; 7145 dev->nDeletedFiles = 0; 7146 dev->nUnlinkedFiles = 0; 7147 dev->nBackgroundDeletions = 0; 7148 dev->oldestDirtySequence = 0; 7149 7150 if(!init_failed && !yaffs_InitialiseBlocks(dev)) 7151 init_failed = 1; 7152 7153 yaffs_InitialiseTnodes(dev); 7154 yaffs_InitialiseObjects(dev); 7155 7156 if(!init_failed && !yaffs_CreateInitialDirectories(dev)) 7157 init_failed = 1; 7158 7159 if(!init_failed && !yaffs_ScanBackwards(dev)) 7160 init_failed = 1; 7161 } 7162 }else 7163 if(!yaffs_Scan(dev)) 7164 init_failed = 1; 7165 } 7166 7167 if(init_failed){ 7168 /* Clean up the mess */ 7169 T(YAFFS_TRACE_TRACING, 7170 (TSTR("yaffs: yaffs_GutsInitialise() aborted.\n" TENDSTR))); 7171 7172 yaffs_Deinitialise(dev); 7173 return YAFFS_FAIL; 7174 } 7175 7176 /* Zero out stats */ 7177 dev->nPageReads = 0; 7178 dev->nPageWrites = 0; 7179 dev->nBlockErasures = 0; 7180 dev->nGCCopies = 0; 7181 dev->nRetriedWrites = 0; 7182 7183 dev->nRetiredBlocks = 0; 7184 7185 yaffs_VerifyFreeChunks(dev); 7186 yaffs_VerifyBlocks(dev); 7187 7188 7189 T(YAFFS_TRACE_TRACING, 7190 (TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR))); 7191 return YAFFS_OK; 7192 7193 } 7194 7195 void yaffs_Deinitialise(yaffs_Device * dev) 7196 { 7197 if (dev->isMounted) { 7198 int i; 7199 7200 yaffs_DeinitialiseBlocks(dev); 7201 yaffs_DeinitialiseTnodes(dev); 7202 yaffs_DeinitialiseObjects(dev); 7203 if (dev->nShortOpCaches > 0 && 7204 dev->srCache) { 7205 7206 for (i = 0; i < dev->nShortOpCaches; i++) { 7207 if(dev->srCache[i].data) 7208 YFREE(dev->srCache[i].data); 7209 dev->srCache[i].data = NULL; 7210 } 7211 7212 YFREE(dev->srCache); 7213 dev->srCache = NULL; 7214 } 7215 7216 YFREE(dev->gcCleanupList); 7217 7218 for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { 7219 YFREE(dev->tempBuffer[i].buffer); 7220 } 7221 7222 dev->isMounted = 0; 7223 } 7224 7225 } 7226 7227 static int yaffs_CountFreeChunks(yaffs_Device * dev) 7228 { 7229 int nFree; 7230 int b; 7231 7232 yaffs_BlockInfo *blk; 7233 7234 for (nFree = 0, b = dev->internalStartBlock; b <= dev->internalEndBlock; 7235 b++) { 7236 blk = yaffs_GetBlockInfo(dev, b); 7237 7238 switch (blk->blockState) { 7239 case YAFFS_BLOCK_STATE_EMPTY: 7240 case YAFFS_BLOCK_STATE_ALLOCATING: 7241 case YAFFS_BLOCK_STATE_COLLECTING: 7242 case YAFFS_BLOCK_STATE_FULL: 7243 nFree += 7244 (dev->nChunksPerBlock - blk->pagesInUse + 7245 blk->softDeletions); 7246 break; 7247 default: 7248 break; 7249 } 7250 7251 } 7252 7253 return nFree; 7254 } 7255 7256 int yaffs_GetNumberOfFreeChunks(yaffs_Device * dev) 7257 { 7258 /* This is what we report to the outside world */ 7259 7260 int nFree; 7261 int nDirtyCacheChunks; 7262 int blocksForCheckpoint; 7263 7264 #if 1 7265 nFree = dev->nFreeChunks; 7266 #else 7267 nFree = yaffs_CountFreeChunks(dev); 7268 #endif 7269 7270 nFree += dev->nDeletedFiles; 7271 7272 /* Now count the number of dirty chunks in the cache and subtract those */ 7273 7274 { 7275 int i; 7276 for (nDirtyCacheChunks = 0, i = 0; i < dev->nShortOpCaches; i++) { 7277 if (dev->srCache[i].dirty) 7278 nDirtyCacheChunks++; 7279 } 7280 } 7281 7282 nFree -= nDirtyCacheChunks; 7283 7284 nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock); 7285 7286 /* Now we figure out how much to reserve for the checkpoint and report that... */ 7287 blocksForCheckpoint = dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint; 7288 if(blocksForCheckpoint < 0) 7289 blocksForCheckpoint = 0; 7290 7291 nFree -= (blocksForCheckpoint * dev->nChunksPerBlock); 7292 7293 if (nFree < 0) 7294 nFree = 0; 7295 7296 return nFree; 7297 7298 } 7299 7300 static int yaffs_freeVerificationFailures; 7301 7302 static void yaffs_VerifyFreeChunks(yaffs_Device * dev) 7303 { 7304 int counted; 7305 int difference; 7306 7307 if(yaffs_SkipVerification(dev)) 7308 return; 7309 7310 counted = yaffs_CountFreeChunks(dev); 7311 7312 difference = dev->nFreeChunks - counted; 7313 7314 if (difference) { 7315 T(YAFFS_TRACE_ALWAYS, 7316 (TSTR("Freechunks verification failure %d %d %d" TENDSTR), 7317 dev->nFreeChunks, counted, difference)); 7318 yaffs_freeVerificationFailures++; 7319 } 7320 } 7321 7322 /*---------------------------------------- YAFFS test code ----------------------*/ 7323 7324 #define yaffs_CheckStruct(structure,syze, name) \ 7325 if(sizeof(structure) != syze) \ 7326 { \ 7327 T(YAFFS_TRACE_ALWAYS,(TSTR("%s should be %d but is %d\n" TENDSTR),\ 7328 name,syze,sizeof(structure))); \ 7329 return YAFFS_FAIL; \ 7330 } 7331 7332 static int yaffs_CheckStructures(void) 7333 { 7334 /* yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags") */ 7335 /* yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion") */ 7336 /* yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare") */ 7337 #ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG 7338 yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode") 7339 #endif 7340 yaffs_CheckStruct(yaffs_ObjectHeader, 512, "yaffs_ObjectHeader") 7341 7342 return YAFFS_OK; 7343 } 7344