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