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