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