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