2 * YAFFS: Yet another FFS. A NAND-flash specific file system.
4 * Copyright (C) 2002 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
7 * Created by Charles Manning <charles@aleph1.co.uk>
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.
16 const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.17 2005-08-09 04:17:30 charles Exp $";
20 #include "yaffsinterface.h"
21 #include "yaffs_guts.h"
22 #include "yaffs_tagsvalidity.h"
25 #include "yaffs_tagscompat.h"
27 #ifdef CONFIG_YAFFS_WINCE
28 void yfsd_LockYAFFS(BOOL fsLockOnly);
29 void yfsd_UnlockYAFFS(BOOL fsLockOnly);
32 #define YAFFS_PASSIVE_GC_CHUNKS 2
35 #include "yaffs_ecc.h"
42 static Y_INLINE int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *buffer, yaffs_ExtendedTags *tags);
43 static Y_INLINE int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND, const __u8 *data, yaffs_ExtendedTags *tags);
44 static Y_INLINE int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo);
45 static Y_INLINE int yaffs_QueryInitialBlockState(yaffs_Device *dev,int blockNo, yaffs_BlockState *state,unsigned *sequenceNumber);
47 static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, const __u8 *buffer, yaffs_ExtendedTags *tags, int useReserve);
48 static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan);
50 static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type);
51 static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj);
52 static int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int isShrink, int shadows);
53 static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj);
54 static int yaffs_CheckStructures(void);
55 static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset,int *limit);
56 static int yaffs_DoGenericObjectDeletion(yaffs_Object *in);
58 static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device *dev,int blockNo);
60 static __u8 *yaffs_GetTempBuffer(yaffs_Device *dev,int lineNo);
61 static void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, int lineNo);
64 // Robustification (if it ever comes about...)
65 static void yaffs_RetireBlock(yaffs_Device *dev,int blockInNAND);
66 static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND);
67 static void yaffs_HandleWriteChunkOk(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *tags);
68 static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND, const yaffs_ExtendedTags *tags);
70 static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND);
72 static int yaffs_UnlinkWorker(yaffs_Object *obj);
73 static void yaffs_DestroyObject(yaffs_Object *obj);
76 static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId, int chunkInObject);
79 loff_t yaffs_GetFileSize(yaffs_Object *obj);
82 static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve);
84 static void yaffs_VerifyFreeChunks(yaffs_Device *dev);
87 static int yaffs_CheckFileSanity(yaffs_Object *in);
89 #define yaffs_CheckFileSanity(in)
92 static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in);
93 static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId);
95 static int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *buffer, yaffs_ExtendedTags *tags)
97 chunkInNAND -= dev->chunkOffset;
99 if(dev->readChunkWithTagsFromNAND)
100 return dev->readChunkWithTagsFromNAND(dev,chunkInNAND,buffer,tags);
102 return yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev,chunkInNAND,buffer,tags);
105 static Y_INLINE int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND, const __u8 *buffer, yaffs_ExtendedTags *tags)
107 chunkInNAND -= dev->chunkOffset;
111 tags->sequenceNumber = dev->sequenceNumber;
113 if(!yaffs_ValidateTags(tags))
115 T(YAFFS_TRACE_ERROR,(TSTR("Writing uninitialised tags" TENDSTR)));
118 T(YAFFS_TRACE_WRITE,(TSTR("Writing chunk %d tags %d %d"TENDSTR),chunkInNAND,tags->objectId,tags->chunkId));
122 T(YAFFS_TRACE_ERROR,(TSTR("Writing with no tags" TENDSTR)));
126 if(dev->writeChunkWithTagsToNAND)
127 return dev->writeChunkWithTagsToNAND(dev,chunkInNAND,buffer,tags);
129 return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev,chunkInNAND,buffer,tags);
132 static Y_INLINE int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo)
134 blockNo -= dev->blockOffset;
136 if(dev->markNANDBlockBad)
137 return dev->markNANDBlockBad(dev,blockNo);
139 return yaffs_TagsCompatabilityMarkNANDBlockBad(dev,blockNo);
141 static Y_INLINE int yaffs_QueryInitialBlockState(yaffs_Device *dev,int blockNo, yaffs_BlockState *state, unsigned *sequenceNumber)
143 blockNo -= dev->blockOffset;
145 if(dev->queryNANDBlock)
146 return dev->queryNANDBlock(dev,blockNo,state,sequenceNumber);
148 return yaffs_TagsCompatabilityQueryNANDBlock(dev,blockNo,state,sequenceNumber);
151 static int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND)
155 blockInNAND -= dev->blockOffset;
157 dev->nBlockErasures++;
158 result = dev->eraseBlockInNAND(dev,blockInNAND);
160 if(!result)result = dev->eraseBlockInNAND(dev,blockInNAND); // If at first we don't succeed, try again *once*.
164 static int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
166 return dev->initialiseNAND(dev);
172 // Temporary buffer manipulations
174 static __u8 *yaffs_GetTempBuffer(yaffs_Device *dev,int lineNo)
177 for(i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
179 if(dev->tempBuffer[i].line == 0)
181 dev->tempBuffer[i].line = lineNo;
182 if((i+1) > dev->maxTemp)
184 dev->maxTemp = i + 1;
185 for(j = 0; j <= i; j++)
186 dev->tempBuffer[j].maxLine = dev->tempBuffer[j].line;
189 return dev->tempBuffer[i].buffer;
193 T(YAFFS_TRACE_BUFFERS,(TSTR("Out of temp buffers at line %d, other held by lines:"),lineNo));
194 for(i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
196 T(YAFFS_TRACE_BUFFERS,(TSTR(" %d "),dev->tempBuffer[i].line));
198 T(YAFFS_TRACE_BUFFERS,(TSTR(" "TENDSTR)));
200 dev->unmanagedTempAllocations++;
201 // Get an unmanaged one
202 return YMALLOC(dev->nBytesPerChunk);
207 static void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, int lineNo)
210 for(i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
212 if(dev->tempBuffer[i].buffer == buffer)
214 dev->tempBuffer[i].line = 0;
221 // assume it is an unmanaged one.
222 T(YAFFS_TRACE_BUFFERS,(TSTR("Releasing unmanaged temp buffer in line %d" TENDSTR),lineNo));
224 dev->unmanagedTempDeallocations++;
230 // Chunk bitmap manipulations
232 static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk)
234 if(blk < dev->internalStartBlock || blk > dev->internalEndBlock)
236 T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),blk));
239 return dev->chunkBits + (dev->chunkBitmapStride * (blk - dev->internalStartBlock));
242 static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device *dev,int blk)
244 __u8 *blkBits = yaffs_BlockBits(dev,blk);
246 memset(blkBits,0,dev->chunkBitmapStride);
249 static Y_INLINE void yaffs_ClearChunkBit(yaffs_Device *dev,int blk,int chunk)
251 __u8 *blkBits = yaffs_BlockBits(dev,blk);
253 blkBits[chunk/8] &= ~ (1<<(chunk & 7));
256 static Y_INLINE void yaffs_SetChunkBit(yaffs_Device *dev,int blk,int chunk)
258 __u8 *blkBits = yaffs_BlockBits(dev,blk);
260 blkBits[chunk/8] |= (1<<(chunk & 7));
263 static Y_INLINE int yaffs_CheckChunkBit(yaffs_Device *dev,int blk,int chunk)
265 __u8 *blkBits = yaffs_BlockBits(dev,blk);
266 return (blkBits[chunk/8] & (1<<(chunk & 7))) ? 1 :0;
269 static Y_INLINE int yaffs_StillSomeChunkBits(yaffs_Device *dev,int blk)
271 __u8 *blkBits = yaffs_BlockBits(dev,blk);
273 for(i = 0; i < dev->chunkBitmapStride; i++)
275 if(*blkBits) return 1;
282 static Y_INLINE int yaffs_HashFunction(int n)
284 return (n % YAFFS_NOBJECT_BUCKETS);
288 yaffs_Object *yaffs_Root(yaffs_Device *dev)
293 yaffs_Object *yaffs_LostNFound(yaffs_Device *dev)
295 return dev->lostNFoundDir;
301 int yaffs_CheckFF(__u8 *buffer,int nBytes)
303 //Horrible, slow implementation
306 if(*buffer != 0xFF) return 0;
312 static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND)
315 int retval = YAFFS_OK;
316 __u8 *data = yaffs_GetTempBuffer(dev,__LINE__);
317 yaffs_ExtendedTags tags;
319 // NCB dev->readChunkWithTagsFromNAND(dev,chunkInNAND,data,&tags);
320 yaffs_ReadChunkWithTagsFromNAND(dev,chunkInNAND,data,&tags);
322 if(!yaffs_CheckFF(data,dev->nBytesPerChunk) || tags.chunkUsed)
324 T(YAFFS_TRACE_NANDACCESS,(TSTR("Chunk %d not erased" TENDSTR),chunkInNAND));
328 yaffs_ReleaseTempBuffer(dev,data,__LINE__);
336 static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, const __u8 *data, yaffs_ExtendedTags *tags,int useReserve)
346 chunk = yaffs_AllocateChunk(dev,useReserve);
351 // First check this chunk is erased...
352 #ifndef CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
353 writeOk = yaffs_CheckChunkErased(dev,chunk);
357 T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs chunk %d was not erased" TENDSTR),chunk));
361 writeOk = yaffs_WriteChunkWithTagsToNAND(dev,chunk,data,tags);
367 // Copy the data into the robustification buffer.
368 // NB We do this at the end to prevent duplicates in the case of a write error.
370 yaffs_HandleWriteChunkOk(dev,chunk,data,tags);
374 yaffs_HandleWriteChunkError(dev,chunk);
378 } while(chunk >= 0 && ! writeOk);
382 T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs write required %d attempts" TENDSTR),attempts));
383 dev->nRetriedWrites+= (attempts - 1);
394 // Functions for robustisizing
398 static void yaffs_RetireBlock(yaffs_Device *dev,int blockInNAND)
401 yaffs_MarkBlockBad(dev,blockInNAND);
403 yaffs_GetBlockInfo(dev,blockInNAND)->blockState = YAFFS_BLOCK_STATE_DEAD;
405 dev->nRetiredBlocks++;
410 static void yaffs_HandleWriteChunkOk(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *tags)
414 static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND, const yaffs_ExtendedTags *tags)
418 static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND)
420 int blockInNAND = chunkInNAND/dev->nChunksPerBlock;
422 // Mark the block for retirement
423 yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1;
425 yaffs_DeleteChunk(dev,chunkInNAND,1,__LINE__);
430 ///////////////////////// Object management //////////////////
431 // List of spare objects
432 // The list is hooked together using the first pointer
435 // static yaffs_Object *yaffs_freeObjects = NULL;
437 // static int yaffs_nFreeObjects;
439 // static yaffs_ObjectList *yaffs_allocatedObjectList = NULL;
441 // static yaffs_ObjectBucket yaffs_objectBucket[YAFFS_NOBJECT_BUCKETS];
444 static __u16 yaffs_CalcNameSum(const YCHAR *name)
449 YUCHAR *bname = (YUCHAR *)name;
452 while ((*bname) && (i <=YAFFS_MAX_NAME_LENGTH))
455 #ifdef CONFIG_YAFFS_CASE_INSENSITIVE
456 sum += yaffs_toupper(*bname) * i;
467 static void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)
469 #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
470 if(name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH)
472 yaffs_strcpy(obj->shortName,name);
476 obj->shortName[0]=_Y('\0');
479 obj->sum = yaffs_CalcNameSum(name);
484 ///////////////////////// TNODES ///////////////////////
486 // List of spare tnodes
487 // The list is hooked together using the first pointer
490 //static yaffs_Tnode *yaffs_freeTnodes = NULL;
492 // static int yaffs_nFreeTnodes;
494 //static yaffs_TnodeList *yaffs_allocatedTnodeList = NULL;
498 // yaffs_CreateTnodes creates a bunch more tnodes and
499 // adds them to the tnode free list.
500 // Don't use this function directly
502 static int yaffs_CreateTnodes(yaffs_Device *dev,int nTnodes)
505 yaffs_Tnode *newTnodes;
506 yaffs_TnodeList *tnl;
508 if(nTnodes < 1) return YAFFS_OK;
512 newTnodes = YMALLOC(nTnodes * sizeof(yaffs_Tnode));
516 T(YAFFS_TRACE_ERROR,(TSTR("yaffs: Could not allocate Tnodes"TENDSTR)));
520 // Hook them into the free list
521 for(i = 0; i < nTnodes - 1; i++)
523 newTnodes[i].internal[0] = &newTnodes[i+1];
524 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
525 newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
529 newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes;
530 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
531 newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
533 dev->freeTnodes = newTnodes;
534 dev->nFreeTnodes+= nTnodes;
535 dev->nTnodesCreated += nTnodes;
537 // Now add this bunch of tnodes to a list for freeing up.
538 // NB If we can't add this to the management list it isn't fatal
539 // but it just means we can't free this bunch of tnodes later.
540 tnl = YMALLOC(sizeof(yaffs_TnodeList));
543 T(YAFFS_TRACE_ERROR,(TSTR("yaffs: Could not add tnodes to management list" TENDSTR)));
548 tnl->tnodes = newTnodes;
549 tnl->next = dev->allocatedTnodeList;
550 dev->allocatedTnodeList = tnl;
554 T(YAFFS_TRACE_ALLOCATE,(TSTR("yaffs: Tnodes added" TENDSTR)));
561 // GetTnode gets us a clean tnode. Tries to make allocate more if we run out
562 static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
564 yaffs_Tnode *tn = NULL;
566 // If there are none left make more
569 yaffs_CreateTnodes(dev,YAFFS_ALLOCATION_NTNODES);
574 tn = dev->freeTnodes;
575 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
576 if(tn->internal[YAFFS_NTNODES_INTERNAL] != (void *)1)
578 // Hoosterman, this thing looks like it isn't in the list
579 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Tnode list bug 1" TENDSTR)));
582 dev->freeTnodes = dev->freeTnodes->internal[0];
585 memset(tn,0,sizeof(yaffs_Tnode));
593 // FreeTnode frees up a tnode and puts it back on the free list
594 static void yaffs_FreeTnode(yaffs_Device*dev, yaffs_Tnode *tn)
598 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
599 if(tn->internal[YAFFS_NTNODES_INTERNAL] != 0)
601 // Hoosterman, this thing looks like it is already in the list
602 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Tnode list bug 2" TENDSTR)));
604 tn->internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
606 tn->internal[0] = dev->freeTnodes;
607 dev->freeTnodes = tn;
613 static void yaffs_DeinitialiseTnodes(yaffs_Device*dev)
615 // Free the list of allocated tnodes
616 yaffs_TnodeList *tmp;
618 while(dev->allocatedTnodeList)
620 tmp = dev->allocatedTnodeList->next;
622 YFREE(dev->allocatedTnodeList->tnodes);
623 YFREE(dev->allocatedTnodeList);
624 dev->allocatedTnodeList = tmp;
628 dev->freeTnodes = NULL;
629 dev->nFreeTnodes = 0;
632 static void yaffs_InitialiseTnodes(yaffs_Device*dev)
634 dev->allocatedTnodeList = NULL;
635 dev->freeTnodes = NULL;
636 dev->nFreeTnodes = 0;
637 dev->nTnodesCreated = 0;
643 ////////////////// END OF TNODE MANIPULATION ///////////////////////////
645 /////////////// Functions to manipulate the look-up tree (made up of tnodes)
646 // The look up tree is represented by the top tnode and the number of topLevel
647 // in the tree. 0 means only the level 0 tnode is in the tree.
650 // FindLevel0Tnode finds the level 0 tnode, if one exists.
651 // Used when reading.....
652 static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,yaffs_FileStructure *fStruct, __u32 chunkId)
655 yaffs_Tnode *tn = fStruct->top;
657 int requiredTallness;
658 int level = fStruct->topLevel;
660 // Check sane level and chunk Id
661 if(level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
664 // sprintf(str,"Bad level %d",level);
669 if(chunkId > YAFFS_MAX_CHUNK_ID)
672 // sprintf(str,"Bad chunkId %d",chunkId);
677 // First check we're tall enough (ie enough topLevel)
679 i = chunkId >> (/*dev->chunkGroupBits + */YAFFS_TNODES_LEVEL0_BITS);
680 requiredTallness = 0;
683 i >>= YAFFS_TNODES_INTERNAL_BITS;
688 if(requiredTallness > fStruct->topLevel)
690 // Not tall enough, so we can't find it, return NULL.
695 // Traverse down to level 0
696 while (level > 0 && tn)
698 tn = tn->internal[(chunkId >>(/* dev->chunkGroupBits + */ YAFFS_TNODES_LEVEL0_BITS + (level-1) * YAFFS_TNODES_INTERNAL_BITS)) &
699 YAFFS_TNODES_INTERNAL_MASK];
707 // AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
708 // This happens in two steps:
709 // 1. If the tree isn't tall enough, then make it taller.
710 // 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
712 // Used when modifying the tree.
714 static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, yaffs_FileStructure *fStruct, __u32 chunkId)
719 int requiredTallness;
726 //T((TSTR("AddOrFind topLevel=%d, chunk=%d"),fStruct->topLevel,chunkId));
728 // Check sane level and page Id
729 if(fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL)
732 // sprintf(str,"Bad level %d",fStruct->topLevel);
737 if(chunkId > YAFFS_MAX_CHUNK_ID)
740 // sprintf(str,"Bad chunkId %d",chunkId);
745 // First check we're tall enough (ie enough topLevel)
747 x = chunkId >> (/*dev->chunkGroupBits + */YAFFS_TNODES_LEVEL0_BITS);
748 requiredTallness = 0;
751 x >>= YAFFS_TNODES_INTERNAL_BITS;
755 //T((TSTR(" required=%d"),requiredTallness));
758 if(requiredTallness > fStruct->topLevel)
760 // Not tall enough,gotta make the tree taller
761 for(i = fStruct->topLevel; i < requiredTallness; i++)
763 //T((TSTR(" add new top")));
765 tn = yaffs_GetTnode(dev);
769 tn->internal[0] = fStruct->top;
774 T(YAFFS_TRACE_ERROR,(TSTR("yaffs: no more tnodes" TENDSTR)));
778 fStruct->topLevel = requiredTallness;
782 // Traverse down to level 0, adding anything we need
784 l = fStruct->topLevel;
788 x = (chunkId >> (/*dev->chunkGroupBits + */YAFFS_TNODES_LEVEL0_BITS + (l-1) * YAFFS_TNODES_INTERNAL_BITS)) &
789 YAFFS_TNODES_INTERNAL_MASK;
791 //T((TSTR(" [%d:%d]"),l,i));
795 //T((TSTR(" added")));
797 tn->internal[x] = yaffs_GetTnode(dev);
800 tn = tn->internal[x];
811 static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk, yaffs_ExtendedTags *tags, int objectId, int chunkInInode)
816 for(j = 0; theChunk && j < dev->chunkGroupSize; j++)
818 if(yaffs_CheckChunkBit(dev,theChunk / dev->nChunksPerBlock,theChunk % dev->nChunksPerBlock))
820 yaffs_ReadChunkWithTagsFromNAND(dev,theChunk,NULL,tags);
821 if(yaffs_TagsMatch(tags,objectId,chunkInInode))
833 // DeleteWorker scans backwards through the tnode tree and deletes all the
834 // chunks and tnodes in the file
835 // Returns 1 if the tree was deleted. Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
837 static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset,int *limit)
842 yaffs_ExtendedTags tags;
844 yaffs_Device *dev = in->myDev;
854 for(i = YAFFS_NTNODES_INTERNAL -1; allDone && i >= 0; i--)
858 if(limit && (*limit) < 0)
864 allDone = yaffs_DeleteWorker(in,tn->internal[i],level - 1,
865 (chunkOffset << YAFFS_TNODES_INTERNAL_BITS ) + i ,limit);
869 yaffs_FreeTnode(dev,tn->internal[i]);
870 tn->internal[i] = NULL;
875 return (allDone) ? 1 : 0;
881 for(i = YAFFS_NTNODES_LEVEL0 -1; i >= 0 && !hitLimit; i--)
886 chunkInInode = (chunkOffset << YAFFS_TNODES_LEVEL0_BITS ) + i;
888 theChunk = tn->level0[i] << dev->chunkGroupBits;
890 foundChunk = yaffs_FindChunkInGroup(dev,theChunk,&tags,in->objectId,chunkInInode);
894 yaffs_DeleteChunk(dev,foundChunk,1,__LINE__);
911 return (i < 0) ? 1 : 0;
923 static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk)
926 yaffs_BlockInfo *theBlock;
928 T(YAFFS_TRACE_DELETION,(TSTR("soft delete chunk %d" TENDSTR),chunk));
930 theBlock = yaffs_GetBlockInfo(dev, chunk/dev->nChunksPerBlock);
933 theBlock->softDeletions++;
938 // SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
939 // All soft deleting does is increment the block's softdelete count and pulls the chunk out
941 // THus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
943 static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset)
948 yaffs_Device *dev = in->myDev;
956 for(i = YAFFS_NTNODES_INTERNAL -1; allDone && i >= 0; i--)
960 allDone = yaffs_SoftDeleteWorker(in,tn->internal[i],level - 1,
961 (chunkOffset << YAFFS_TNODES_INTERNAL_BITS ) + i);
964 yaffs_FreeTnode(dev,tn->internal[i]);
965 tn->internal[i] = NULL;
969 //Hoosterman... how could this happen.
973 return (allDone) ? 1 : 0;
978 for(i = YAFFS_NTNODES_LEVEL0 -1; i >=0; i--)
982 // Note this does not find the real chunk, only the chunk group.
983 // We make an assumption that a chunk group is niot larger than a block.
984 theChunk = (tn->level0[i] << dev->chunkGroupBits);
986 yaffs_SoftDeleteChunk(dev,theChunk);
1003 static void yaffs_SoftDeleteFile(yaffs_Object *obj)
1006 obj->variantType == YAFFS_OBJECT_TYPE_FILE &&
1009 if(obj->nDataChunks <= 0)
1011 // Empty file with no duplicate object headers, just delete it immediately
1012 yaffs_FreeTnode(obj->myDev,obj->variant.fileVariant.top);
1013 obj->variant.fileVariant.top = NULL;
1014 T(YAFFS_TRACE_TRACING,(TSTR("yaffs: Deleting empty file %d" TENDSTR),obj->objectId));
1015 yaffs_DoGenericObjectDeletion(obj);
1019 yaffs_SoftDeleteWorker(obj, obj->variant.fileVariant.top, obj->variant.fileVariant.topLevel, 0);
1020 obj->softDeleted = 1;
1029 // Pruning removes any part of the file structure tree that is beyond the
1030 // bounds of the file (ie that does not point to chunks).
1032 // A file should only get pruned when its size is reduced.
1034 // Before pruning, the chunks must be pulled from the tree and the
1035 // level 0 tnode entries must be zeroed out.
1036 // Could also use this for file deletion, but that's probably better handled
1037 // by a special case.
1039 // yaffs_PruneWorker should only be called by yaffs_PruneFileStructure()
1041 static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn, __u32 level, int del0)
1050 for(i = 0; i < YAFFS_NTNODES_INTERNAL; i++)
1052 if(tn->internal[i] && level > 0)
1054 tn->internal[i] = yaffs_PruneWorker(dev,tn->internal[i],level - 1, ( i == 0) ? del0 : 1);
1063 if(hasData == 0 && del0)
1065 // Free and return NULL
1067 yaffs_FreeTnode(dev,tn);
1077 static int yaffs_PruneFileStructure(yaffs_Device *dev, yaffs_FileStructure *fStruct)
1084 if(fStruct->topLevel > 0)
1086 fStruct->top = yaffs_PruneWorker(dev,fStruct->top, fStruct->topLevel,0);
1088 // Now we have a tree with all the non-zero branches NULL but the height
1089 // is the same as it was.
1090 // Let's see if we can trim internal tnodes to shorten the tree.
1091 // We can do this if only the 0th element in the tnode is in use
1092 // (ie all the non-zero are NULL)
1094 while(fStruct->topLevel && !done)
1099 for(i = 1; i <YAFFS_NTNODES_INTERNAL; i++)
1109 fStruct->top = tn->internal[0];
1110 fStruct->topLevel--;
1111 yaffs_FreeTnode(dev,tn);
1127 /////////////////////// End of File Structure functions. /////////////////
1129 // yaffs_CreateFreeObjects creates a bunch more objects and
1130 // adds them to the object free list.
1131 static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
1134 yaffs_Object *newObjects;
1135 yaffs_ObjectList *list;
1137 if(nObjects < 1) return YAFFS_OK;
1139 // make these things
1141 newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
1145 T(YAFFS_TRACE_ALLOCATE,(TSTR("yaffs: Could not allocate more objects" TENDSTR)));
1149 // Hook them into the free list
1150 for(i = 0; i < nObjects - 1; i++)
1152 newObjects[i].siblings.next = (struct list_head *)(&newObjects[i+1]);
1155 newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects;
1156 dev->freeObjects = newObjects;
1157 dev->nFreeObjects+= nObjects;
1158 dev->nObjectsCreated+= nObjects;
1160 // Now add this bunch of Objects to a list for freeing up.
1162 list = YMALLOC(sizeof(yaffs_ObjectList));
1165 T(YAFFS_TRACE_ALLOCATE,(TSTR("Could not add objects to management list" TENDSTR)));
1169 list->objects = newObjects;
1170 list->next = dev->allocatedObjectList;
1171 dev->allocatedObjectList = list;
1180 // AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out
1181 static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev)
1183 yaffs_Object *tn = NULL;
1185 // If there are none left make more
1186 if(!dev->freeObjects)
1188 yaffs_CreateFreeObjects(dev,YAFFS_ALLOCATION_NOBJECTS);
1191 if(dev->freeObjects)
1193 tn = dev->freeObjects;
1194 dev->freeObjects = (yaffs_Object *)(dev->freeObjects->siblings.next);
1195 dev->nFreeObjects--;
1197 // Now sweeten it up...
1199 memset(tn,0,sizeof(yaffs_Object));
1202 tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
1203 INIT_LIST_HEAD(&(tn->hardLinks));
1204 INIT_LIST_HEAD(&(tn->hashLink));
1205 INIT_LIST_HEAD(&tn->siblings);
1207 // Add it to the lost and found directory.
1208 // NB Can't put root or lostNFound in lostNFound so
1209 // check if lostNFound exists first
1210 if(dev->lostNFoundDir)
1212 yaffs_AddObjectToDirectory(dev->lostNFoundDir,tn);
1220 static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev,int number,__u32 mode)
1223 yaffs_Object *obj = yaffs_CreateNewObject(dev,number,YAFFS_OBJECT_TYPE_DIRECTORY);
1226 obj->fake = 1; // it is fake so it has no NAND presence...
1227 obj->renameAllowed= 0; // ... and we're not allowed to rename it...
1228 obj->unlinkAllowed= 0; // ... or unlink it
1231 obj->yst_mode = mode;
1233 obj->chunkId = 0; // Not a valid chunk.
1241 static void yaffs_UnhashObject(yaffs_Object *tn)
1244 yaffs_Device *dev = tn->myDev;
1247 // If it is still linked into the bucket list, free from the list
1248 if(!list_empty(&tn->hashLink))
1250 list_del_init(&tn->hashLink);
1251 bucket = yaffs_HashFunction(tn->objectId);
1252 dev->objectBucket[bucket].count--;
1258 // FreeObject frees up a Object and puts it back on the free list
1259 static void yaffs_FreeObject(yaffs_Object *tn)
1262 yaffs_Device *dev = tn->myDev;
1267 // We're still hooked up to a cached inode.
1268 // Don't delete now, but mark for later deletion
1269 tn->deferedFree = 1;
1274 yaffs_UnhashObject(tn);
1276 // Link into the free list.
1277 tn->siblings.next = (struct list_head *)(dev->freeObjects);
1278 dev->freeObjects = tn;
1279 dev->nFreeObjects++;
1286 void yaffs_HandleDeferedFree(yaffs_Object *obj)
1288 if(obj->deferedFree)
1290 yaffs_FreeObject(obj);
1298 static void yaffs_DeinitialiseObjects(yaffs_Device *dev)
1300 // Free the list of allocated Objects
1302 yaffs_ObjectList *tmp;
1304 while( dev->allocatedObjectList)
1306 tmp = dev->allocatedObjectList->next;
1307 YFREE(dev->allocatedObjectList->objects);
1308 YFREE(dev->allocatedObjectList);
1310 dev->allocatedObjectList = tmp;
1313 dev->freeObjects = NULL;
1314 dev->nFreeObjects = 0;
1317 static void yaffs_InitialiseObjects(yaffs_Device *dev)
1321 dev->allocatedObjectList = NULL;
1322 dev->freeObjects = NULL;
1323 dev->nFreeObjects = 0;
1325 for(i = 0; i < YAFFS_NOBJECT_BUCKETS; i++)
1327 INIT_LIST_HEAD(&dev->objectBucket[i].list);
1328 dev->objectBucket[i].count = 0;
1338 static int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
1343 int lowest = 999999;
1346 // First let's see if we can find one that's empty.
1348 for(i = 0; i < 10 && lowest > 0; i++)
1351 x %= YAFFS_NOBJECT_BUCKETS;
1352 if(dev->objectBucket[x].count < lowest)
1354 lowest = dev->objectBucket[x].count;
1360 // If we didn't find an empty list, then try
1361 // looking a bit further for a short one
1363 for(i = 0; i < 10 && lowest > 3; i++)
1366 x %= YAFFS_NOBJECT_BUCKETS;
1367 if(dev->objectBucket[x].count < lowest)
1369 lowest = dev->objectBucket[x].count;
1378 static int yaffs_CreateNewObjectNumber(yaffs_Device *dev)
1380 int bucket = yaffs_FindNiceObjectBucket(dev);
1382 // Now find an object value that has not already been taken
1383 // by scanning the list.
1386 struct list_head *i;
1388 __u32 n = (__u32)bucket;
1390 //yaffs_CheckObjectHashSanity();
1395 n += YAFFS_NOBJECT_BUCKETS;
1396 if(1 ||dev->objectBucket[bucket].count > 0)
1398 list_for_each(i,&dev->objectBucket[bucket].list)
1400 // If there is already one in the list
1401 if(i && list_entry(i, yaffs_Object,hashLink)->objectId == n)
1409 //T(("bucket %d count %d inode %d\n",bucket,yaffs_objectBucket[bucket].count,n);
1414 static void yaffs_HashObject(yaffs_Object *in)
1416 int bucket = yaffs_HashFunction(in->objectId);
1417 yaffs_Device *dev = in->myDev;
1419 if(!list_empty(&in->hashLink))
1425 list_add(&in->hashLink,&dev->objectBucket[bucket].list);
1426 dev->objectBucket[bucket].count++;
1430 yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev,__u32 number)
1432 int bucket = yaffs_HashFunction(number);
1433 struct list_head *i;
1436 list_for_each(i,&dev->objectBucket[bucket].list)
1438 // Look if it is in the list
1441 in = list_entry(i, yaffs_Object,hashLink);
1442 if(in->objectId == number)
1445 // Don't tell the VFS about this one if it is defered free
1460 yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type)
1463 yaffs_Object *theObject;
1467 number = yaffs_CreateNewObjectNumber(dev);
1470 theObject = yaffs_AllocateEmptyObject(dev);
1474 theObject->fake = 0;
1475 theObject->renameAllowed = 1;
1476 theObject->unlinkAllowed = 1;
1477 theObject->objectId = number;
1478 yaffs_HashObject(theObject);
1479 theObject->variantType = type;
1480 #ifdef CONFIG_YAFFS_WINCE
1481 yfsd_WinFileTimeNow(theObject->win_atime);
1482 theObject->win_ctime[0] = theObject->win_mtime[0] = theObject->win_atime[0];
1483 theObject->win_ctime[1] = theObject->win_mtime[1] = theObject->win_atime[1];
1487 theObject->yst_atime = theObject->yst_mtime = theObject->yst_ctime = Y_CURRENT_TIME;
1491 case YAFFS_OBJECT_TYPE_FILE:
1492 theObject->variant.fileVariant.fileSize = 0;
1493 theObject->variant.fileVariant.scannedFileSize = 0;
1494 theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; // max __u32
1495 theObject->variant.fileVariant.topLevel = 0;
1496 theObject->variant.fileVariant.top = yaffs_GetTnode(dev);
1498 case YAFFS_OBJECT_TYPE_DIRECTORY:
1499 INIT_LIST_HEAD(&theObject->variant.directoryVariant.children);
1501 case YAFFS_OBJECT_TYPE_SYMLINK:
1502 // No action required
1504 case YAFFS_OBJECT_TYPE_HARDLINK:
1505 // No action required
1507 case YAFFS_OBJECT_TYPE_SPECIAL:
1508 // No action required
1510 case YAFFS_OBJECT_TYPE_UNKNOWN:
1511 // todo this should not happen
1519 static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, int number,yaffs_ObjectType type)
1521 yaffs_Object *theObject = NULL;
1525 theObject = yaffs_FindObjectByNumber(dev,number);
1530 theObject = yaffs_CreateNewObject(dev,number,type);
1537 static YCHAR *yaffs_CloneString(const YCHAR *str)
1539 YCHAR *newStr = NULL;
1543 newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR));
1544 yaffs_strcpy(newStr,str);
1552 // Mknod (create) a new object.
1553 // equivalentObject only has meaning for a hard link;
1554 // aliasString only has meaning for a sumlink.
1555 // rdev only has meaning for devices (a subset of special objects)
1556 static yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type,
1557 yaffs_Object *parent,
1562 yaffs_Object *equivalentObject,
1563 const YCHAR *aliasString,
1568 yaffs_Device *dev = parent->myDev;
1570 // Check if the entry exists. If it does then fail the call since we don't want a dup.
1571 if(yaffs_FindObjectByName(parent,name))
1576 in = yaffs_CreateNewObject(dev,-1,type);
1582 in->variantType = type;
1584 in->yst_mode = mode;
1586 #ifdef CONFIG_YAFFS_WINCE
1587 yfsd_WinFileTimeNow(in->win_atime);
1588 in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];
1589 in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
1592 in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;
1594 in->yst_rdev = rdev;
1598 in->nDataChunks = 0;
1600 yaffs_SetObjectName(in,name);
1603 yaffs_AddObjectToDirectory(parent,in);
1605 in->myDev = parent->myDev;
1610 case YAFFS_OBJECT_TYPE_SYMLINK:
1611 in->variant.symLinkVariant.alias = yaffs_CloneString(aliasString);
1613 case YAFFS_OBJECT_TYPE_HARDLINK:
1614 in->variant.hardLinkVariant.equivalentObject = equivalentObject;
1615 in->variant.hardLinkVariant.equivalentObjectId = equivalentObject->objectId;
1616 list_add(&in->hardLinks,&equivalentObject->hardLinks);
1618 case YAFFS_OBJECT_TYPE_FILE: // do nothing
1619 case YAFFS_OBJECT_TYPE_DIRECTORY: // do nothing
1620 case YAFFS_OBJECT_TYPE_SPECIAL: // do nothing
1621 case YAFFS_OBJECT_TYPE_UNKNOWN:
1625 if(/*yaffs_GetNumberOfFreeChunks(dev) <= 0 || */
1626 yaffs_UpdateObjectHeader(in,name,0,0,0) < 0)
1628 // Could not create the object header, fail the creation
1629 yaffs_DestroyObject(in);
1638 yaffs_Object *yaffs_MknodFile(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid)
1640 return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE,parent,name,mode,uid,gid,NULL,NULL,0);
1643 yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid)
1645 return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY,parent,name,mode,uid,gid,NULL,NULL,0);
1648 yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid, __u32 rdev)
1650 return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL,parent,name,mode,uid,gid,NULL,NULL,rdev);
1653 yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid,const YCHAR *alias)
1655 return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK,parent,name,mode,uid,gid,NULL,alias,0);
1658 // NB yaffs_Link returns the object id of the equivalent object.
1659 yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name, yaffs_Object *equivalentObject)
1661 // Get the real object in case we were fed a hard link as an equivalent object
1662 equivalentObject = yaffs_GetEquivalentObject(equivalentObject);
1664 if(yaffs_MknodObject(YAFFS_OBJECT_TYPE_HARDLINK,parent,name,0,0,0,equivalentObject,NULL,0))
1666 return equivalentObject;
1676 static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const YCHAR *newName,int force,int shadows)
1681 yaffs_Object * existingTarget;
1685 newDir = obj->parent; // use the old directory
1688 if(newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
1690 T(YAFFS_TRACE_ALWAYS,(TSTR("tragendy: yaffs_ChangeObjectName: newDir is not a directory"TENDSTR)));
1694 // TODO: Do we need this different handling for YAFFS2 and YAFFS1??
1695 if(obj->myDev->isYaffs2)
1697 unlinkOp = (newDir == obj->myDev->unlinkedDir);
1701 unlinkOp = (newDir == obj->myDev->unlinkedDir && obj->variantType == YAFFS_OBJECT_TYPE_FILE);
1704 deleteOp = (newDir == obj->myDev->deletedDir);
1706 existingTarget = yaffs_FindObjectByName(newDir,newName);
1708 // If the object is a file going into the unlinked directory, then it is OK to just stuff it in since
1709 // duplicate names are allowed.
1710 // Otherwise only proceed if the new name does not exist and if we're putting it into a directory.
1716 newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
1718 yaffs_SetObjectName(obj,newName);
1721 yaffs_AddObjectToDirectory(newDir,obj);
1723 if(unlinkOp) obj->unlinked = 1;
1725 // If it is a deletion then we mark it as a shrink for gc purposes.
1726 if(yaffs_UpdateObjectHeader(obj,newName,0,deleteOp,shadows) >= 0)
1737 int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName, yaffs_Object *newDir, const YCHAR *newName)
1740 yaffs_Object *existingTarget;
1743 #ifdef CONFIG_YAFFS_CASE_INSENSITIVE
1744 // Special case for case insemsitive systems (eg. WinCE).
1745 // While look-up is case insensitive, the name isn't.
1746 // THerefore we might want to change x.txt to X.txt
1747 if(oldDir == newDir && yaffs_strcmp(oldName,newName) == 0)
1753 obj = yaffs_FindObjectByName(oldDir,oldName);
1755 if(obj && obj->renameAllowed)
1758 // Now do the handling for an existing target, if there is one
1760 existingTarget = yaffs_FindObjectByName(newDir,newName);
1761 if(existingTarget &&
1762 existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
1763 !list_empty(&existingTarget->variant.directoryVariant.children))
1765 // There is a target that is a non-empty directory, so we have to fail
1766 return YAFFS_FAIL; // EEXIST or ENOTEMPTY
1768 else if(existingTarget &&
1769 existingTarget != obj)
1771 // Nuke the target first, using shadowing,
1772 // but only if it isn't the same object
1773 yaffs_ChangeObjectName(obj,newDir,newName,force,existingTarget->objectId);
1774 yaffs_Unlink(newDir,newName);
1778 return yaffs_ChangeObjectName(obj,newDir,newName,force,0);
1785 /////////////////////////// Block Management and Page Allocation ///////////////////
1788 static int yaffs_InitialiseBlocks(yaffs_Device *dev,int nBlocks)
1790 dev->allocationBlock = -1; // force it to get a new one
1791 //Todo we're assuming the malloc will pass.
1792 dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo));
1793 // Set up dynamic blockinfo stuff.
1794 dev->chunkBitmapStride = (dev->nChunksPerBlock+7)/8;
1795 dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks);
1796 if(dev->blockInfo && dev->chunkBits)
1798 memset(dev->blockInfo,0,nBlocks * sizeof(yaffs_BlockInfo));
1799 memset(dev->chunkBits,0,dev->chunkBitmapStride * nBlocks);
1807 static void yaffs_DeinitialiseBlocks(yaffs_Device *dev)
1809 YFREE(dev->blockInfo);
1810 dev->blockInfo = NULL;
1811 YFREE(dev->chunkBits);
1812 dev->chunkBits = NULL;
1816 static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device *dev, yaffs_BlockInfo *bi)
1822 if(!dev->isYaffs2) return 1; // disqualification only applies to yaffs2.
1824 if(!bi->hasShrinkHeader) return 1; // can gc
1827 // Find the oldest dirty sequence number if we don't know it and save it
1828 // so we don't have to keep recomputing it.
1829 if(!dev->oldestDirtySequence)
1831 seq = dev->sequenceNumber;
1833 for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++)
1835 b = yaffs_GetBlockInfo(dev,i);
1836 if(b->blockState == YAFFS_BLOCK_STATE_FULL &&
1837 (b->pagesInUse - b->softDeletions )< dev->nChunksPerBlock &&
1838 b->sequenceNumber < seq)
1840 seq = b->sequenceNumber;
1843 dev->oldestDirtySequence = seq;
1847 // Can't do gc of this block if there are any blocks older than this one that have
1849 return (bi->sequenceNumber <= dev->oldestDirtySequence);
1856 // FindDiretiestBlock is used to select the dirtiest block (or close enough)
1857 // for garbage collection.
1862 static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,int aggressive)
1865 int b = dev->currentDirtyChecker;
1871 yaffs_BlockInfo *bi;
1872 static int nonAggressiveSkip = 0;
1874 // If we're doing aggressive GC then we are happy to take a less-dirty block, and
1876 // else (we're doing a leasurely gc), then we only bother to do this if the
1877 // block has only a few pages in use.
1880 nonAggressiveSkip--;
1882 if(!aggressive &&(nonAggressiveSkip > 0))
1887 pagesInUse = (aggressive)? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1;
1891 iterations = dev->internalEndBlock - dev->internalStartBlock + 1;
1895 iterations = dev->internalEndBlock - dev->internalStartBlock + 1;
1896 iterations = iterations / 16;
1897 if(iterations > 200)
1903 for(i = 0; i <= iterations && pagesInUse > 0 ; i++)
1906 if ( b < dev->internalStartBlock || b > dev->internalEndBlock)
1908 b = dev->internalStartBlock;
1911 if(b < dev->internalStartBlock || b > dev->internalEndBlock)
1913 T(YAFFS_TRACE_ERROR,(TSTR("**>> Block %d is not valid" TENDSTR),b));
1917 bi = yaffs_GetBlockInfo(dev,b);
1919 if(bi->blockState == YAFFS_BLOCK_STATE_FULL &&
1920 (bi->pagesInUse - bi->softDeletions )< pagesInUse &&
1921 yaffs_BlockNotDisqualifiedFromGC(dev,bi))
1924 pagesInUse = (bi->pagesInUse - bi->softDeletions);
1928 dev->currentDirtyChecker = b;
1932 T(YAFFS_TRACE_GC,(TSTR("GC Selected block %d with %d free" TENDSTR),dirtiest,dev->nChunksPerBlock - pagesInUse));
1935 dev->oldestDirtySequence = 0; // clear this
1939 nonAggressiveSkip = 4;
1946 static void yaffs_BlockBecameDirty(yaffs_Device *dev,int blockNo)
1948 yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,blockNo);
1952 // If the block is still healthy erase it and mark as clean.
1953 // If the block has had a data failure, then retire it.
1954 bi->blockState = YAFFS_BLOCK_STATE_DIRTY;
1956 if(!bi->needsRetiring)
1958 erasedOk = yaffs_EraseBlockInNAND(dev,blockNo);
1961 dev->nErasureFailures++;
1962 T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>> Erasure failed %d" TENDSTR),blockNo));
1966 if(erasedOk && (yaffs_traceMask & YAFFS_TRACE_ERASE))
1969 for(i = 0; i < dev->nChunksPerBlock; i++)
1971 if(!yaffs_CheckChunkErased(dev,blockNo * dev->nChunksPerBlock + i))
1973 T(YAFFS_TRACE_ERROR,(TSTR(">>Block %d erasure supposedly OK, but chunk %d not erased" TENDSTR),blockNo,i));
1981 bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
1982 dev->nErasedBlocks++;
1984 bi->softDeletions = 0;
1985 bi->hasShrinkHeader=0;
1986 yaffs_ClearChunkBits(dev,blockNo);
1988 T(YAFFS_TRACE_ERASE,(TSTR("Erased block %d" TENDSTR),blockNo));
1992 dev->nFreeChunks -= dev->nChunksPerBlock; // We lost a block of free space
1994 yaffs_RetireBlock(dev,blockNo);
1995 T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>> Block %d retired" TENDSTR),blockNo));
2000 static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
2004 yaffs_BlockInfo *bi;
2006 if(dev->nErasedBlocks < 1)
2008 // Hoosterman we've got a problem.
2009 // Can't get space to gc
2010 T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: no more eraased blocks" TENDSTR)));
2015 // Find an empty block.
2017 for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++)
2019 dev->allocationBlockFinder++;
2020 if(dev->allocationBlockFinder < dev->internalStartBlock || dev->allocationBlockFinder> dev->internalEndBlock)
2022 dev->allocationBlockFinder = dev->internalStartBlock;
2025 bi = yaffs_GetBlockInfo(dev,dev->allocationBlockFinder);
2027 if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
2029 bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING;
2030 dev->sequenceNumber++;
2031 bi->sequenceNumber = dev->sequenceNumber;
2032 dev->nErasedBlocks--;
2033 T(YAFFS_TRACE_ALLOCATE,(TSTR("Allocated block %d, seq %d, %d left" TENDSTR),dev->allocationBlockFinder,dev->sequenceNumber, dev->nErasedBlocks));
2034 return dev->allocationBlockFinder;
2039 T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs tragedy: no more eraased blocks, but there should have been %d" TENDSTR),dev->nErasedBlocks));
2049 // To determine if we have enough space we just look at the
2050 // number of erased blocks.
2052 static int yaffs_CheckSpaceForAllocation(yaffs_Device *dev)
2054 int reservedChunks = (dev->nReservedBlocks * dev->nChunksPerBlock);
2055 return (dev->nFreeChunks > reservedChunks);
2059 static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve)
2062 yaffs_BlockInfo *bi;
2064 if(dev->allocationBlock < 0)
2066 // Get next block to allocate off
2067 dev->allocationBlock = yaffs_FindBlockForAllocation(dev);
2068 dev->allocationPage = 0;
2071 if(!useReserve && !yaffs_CheckSpaceForAllocation(dev))
2073 // Not enough space to allocate unless we're allowed to use the reserve.
2077 if(dev->nErasedBlocks < dev->nReservedBlocks && dev->allocationPage == 0)
2079 T(YAFFS_TRACE_ALLOCATE,(TSTR("Allocating reserve" TENDSTR)));
2083 // Next page please....
2084 if(dev->allocationBlock >= 0)
2086 bi = yaffs_GetBlockInfo(dev,dev->allocationBlock);
2088 retVal = (dev->allocationBlock * dev->nChunksPerBlock) +
2089 dev->allocationPage;
2091 yaffs_SetChunkBit(dev,dev->allocationBlock,dev->allocationPage);
2093 dev->allocationPage++;
2097 // If the block is full set the state to full
2098 if(dev->allocationPage >= dev->nChunksPerBlock)
2100 bi->blockState = YAFFS_BLOCK_STATE_FULL;
2101 dev->allocationBlock = -1;
2108 T(YAFFS_TRACE_ERROR,(TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));
2116 static int yaffs_GetErasedChunks(yaffs_Device *dev)
2120 n = dev->nErasedBlocks * dev->nChunksPerBlock;
2122 if(dev->allocationBlock> 0)
2124 n += (dev->nChunksPerBlock - dev->allocationPage);
2131 static int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
2137 int retVal = YAFFS_OK;
2141 int chunksBefore = yaffs_GetErasedChunks(dev);
2144 yaffs_ExtendedTags tags;
2146 yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,block);
2148 yaffs_Object *object;
2150 bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
2152 T(YAFFS_TRACE_TRACING,(TSTR("Collecting block %d, in use %d, shrink %d, " TENDSTR),block,bi->pagesInUse,bi->hasShrinkHeader));
2153 //T(("Collecting block %d n %d bits %x\n",block, bi->pagesInUse, bi->pageBits));
2155 //yaffs_VerifyFreeChunks(dev);
2157 bi->hasShrinkHeader = 0; // clear the flag so that the block can erase
2159 dev->nFreeChunks -= bi->softDeletions; // Take off the number of soft deleted entries because
2160 // they're going to get really deleted during GC.
2164 if(!yaffs_StillSomeChunkBits(dev,block))
2166 T(YAFFS_TRACE_TRACING,(TSTR("Collecting block %d that has no chunks in use" TENDSTR),block));
2167 yaffs_BlockBecameDirty(dev,block);
2172 __u8 *buffer = yaffs_GetTempBuffer(dev,__LINE__);
2174 for(chunkInBlock = 0,oldChunk = block * dev->nChunksPerBlock;
2175 chunkInBlock < dev->nChunksPerBlock && yaffs_StillSomeChunkBits(dev,block);
2176 chunkInBlock++, oldChunk++ )
2178 if(yaffs_CheckChunkBit(dev,block,chunkInBlock))
2181 // This page is in use and might need to be copied off
2185 //T(("copying page %x from %d to %d\n",mask,oldChunk,newChunk));
2187 yaffs_InitialiseTags(&tags);
2189 yaffs_ReadChunkWithTagsFromNAND(dev,oldChunk,buffer, &tags);
2191 object = yaffs_FindObjectByNumber(dev,tags.objectId);
2193 T(YAFFS_TRACE_GC_DETAIL,(TSTR("Collecting page %d, %d %d %d " TENDSTR),chunkInBlock,tags.objectId,tags.chunkId,tags.byteCount));
2197 T(YAFFS_TRACE_ERROR,(TSTR("page %d in gc has no object " TENDSTR),oldChunk));
2200 if(object && object->deleted && tags.chunkId != 0)
2202 // Data chunk in a deleted file, throw it away
2203 // It's a soft deleted data chunk,
2204 // No need to copy this, just forget about it and fix up the
2207 //yaffs_PutChunkIntoFile(object, tags.chunkId, 0,0);
2208 object->nDataChunks--;
2210 if(object->nDataChunks <= 0)
2212 // remeber to clean up the object
2213 dev->gcCleanupList[cleanups] = tags.objectId;
2218 else if( 0 /* Todo object && object->deleted && object->nDataChunks == 0 */)
2220 // Deleted object header with no data chunks.
2221 // Can be discarded and the file deleted.
2222 object->chunkId = 0;
2223 yaffs_FreeTnode(object->myDev,object->variant.fileVariant.top);
2224 object->variant.fileVariant.top = NULL;
2225 yaffs_DoGenericObjectDeletion(object);
2230 // It's either a data chunk in a live file or
2231 // an ObjectHeader, so we're interested in it.
2232 // NB Need to keep the ObjectHeaders of deleted files
2233 // until the whole file has been deleted off
2234 tags.serialNumber++;
2238 if(tags.chunkId == 0)
2240 // It is an object Id,
2241 // We need to nuke the shrinkheader flags first
2242 // We no longer want the shrinkHeader flag since its work is done
2243 // and if it is left in place it will mess up scanning.
2244 // Also, clear out any shadowing stuff
2246 yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)buffer;
2248 oh->shadowsObject = -1;
2249 tags.extraShadows = 0;
2250 tags.extraIsShrinkHeader = 0;
2253 newChunk = yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags,1);
2257 retVal = YAFFS_FAIL;
2262 // Ok, now fix up the Tnodes etc.
2264 if(tags.chunkId == 0)
2267 object->chunkId = newChunk;
2268 object->serial = tags.serialNumber;
2272 // It's a data chunk
2273 yaffs_PutChunkIntoFile(object, tags.chunkId, newChunk,0);
2278 yaffs_DeleteChunk(dev,oldChunk,markNAND,__LINE__);
2283 yaffs_ReleaseTempBuffer(dev,buffer,__LINE__);
2285 //yaffs_VerifyFreeChunks(dev);
2287 // Do any required cleanups
2288 for(i = 0; i < cleanups; i++)
2290 // Time to delete the file too
2291 object = yaffs_FindObjectByNumber(dev,dev->gcCleanupList[i]);
2294 yaffs_FreeTnode(dev,object->variant.fileVariant.top);
2295 object->variant.fileVariant.top = NULL;
2296 T(YAFFS_TRACE_GC,(TSTR("yaffs: About to finally delete object %d" TENDSTR),object->objectId));
2297 yaffs_DoGenericObjectDeletion(object);
2304 if(chunksBefore >= (chunksAfter = yaffs_GetErasedChunks(dev)))
2306 T(YAFFS_TRACE_GC,(TSTR("gc did not increase free chunks before %d after %d" TENDSTR),chunksBefore,chunksAfter));
2312 //yaffs_VerifyFreeChunks(dev);
2318 // New garbage collector
2319 // If we're very low on erased blocks then we do aggressive garbage collection
2320 // otherwise we do "leasurely" garbage collection.
2321 // Aggressive gc looks further (whole array) and will accept dirtier blocks.
2322 // Passive gc only inspects smaller areas and will only accept cleaner blocks.
2324 // The idea is to help clear out space in a more spread-out manner.
2325 // Dunno if it really does anything useful.
2327 static int yaffs_CheckGarbageCollection(yaffs_Device *dev)
2331 int gcOk = YAFFS_OK;
2334 //yaffs_VerifyFreeChunks(dev);
2338 // Bail out so we don't get recursive gc
2342 // This loop should pass the first time.
2343 // We'll only see looping here if the erase of the collected block fails.
2347 if(dev->nErasedBlocks < dev->nReservedBlocks)
2349 // We need a block soon...
2354 // We're in no hurry
2358 block = yaffs_FindBlockForGarbageCollection(dev,aggressive);
2362 dev->garbageCollections++;
2365 dev->passiveGarbageCollections++;
2368 T(YAFFS_TRACE_GC,(TSTR("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),dev->nErasedBlocks,aggressive));
2370 gcOk = yaffs_GarbageCollectBlock(dev,block);
2373 if(dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0)
2375 T(YAFFS_TRACE_GC,(TSTR("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d" TENDSTR),dev->nErasedBlocks,maxTries,block));
2377 } while((dev->nErasedBlocks < dev->nReservedBlocks) && (block > 0) && (maxTries < 2));
2379 return aggressive ? gcOk: YAFFS_OK;
2383 //////////////////////////// TAGS ///////////////////////////////////////
2387 static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId, int chunkInObject)
2389 return ( tags->chunkId == chunkInObject &&
2390 tags->objectId == objectId &&
2391 !tags->chunkDeleted) ? 1 : 0;
2395 /////////////////////////////////////////////////////////////////////////////////////////////////////////
2398 static int yaffs_FindChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags *tags)
2400 //Get the Tnode, then get the level 0 offset chunk offset
2403 yaffs_ExtendedTags localTags;
2406 yaffs_Device *dev = in->myDev;
2411 // Passed a NULL, so use our own tags space
2415 tn = yaffs_FindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
2419 theChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits;
2421 retVal = yaffs_FindChunkInGroup(dev,theChunk,tags,in->objectId,chunkInInode);
2426 static int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags *tags)
2428 //Get the Tnode, then get the level 0 offset chunk offset
2431 yaffs_ExtendedTags localTags;
2433 yaffs_Device *dev = in->myDev;
2438 // Passed a NULL, so use our own tags space
2442 tn = yaffs_FindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
2447 theChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits;
2449 retVal = yaffs_FindChunkInGroup(dev,theChunk,tags,in->objectId,chunkInInode);
2451 // Delete the entry in the filestructure (if found)
2454 tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] = 0;
2459 //T(("No level 0 found for %d\n", chunkInInode));
2464 //T(("Could not find %d to delete\n",chunkInInode));
2470 #ifdef YAFFS_PARANOID
2472 static int yaffs_CheckFileSanity(yaffs_Object *in)
2480 yaffs_Tags localTags;
2481 yaffs_Tags *tags = &localTags;
2486 if(in->variantType != YAFFS_OBJECT_TYPE_FILE)
2488 //T(("Object not a file\n"));
2492 objId = in->objectId;
2493 fSize = in->variant.fileVariant.fileSize;
2494 nChunks = (fSize + in->myDev->nBytesPerChunk -1)/in->myDev->nBytesPerChunk;
2496 for(chunk = 1; chunk <= nChunks; chunk++)
2498 tn = yaffs_FindLevel0Tnode(in->myDev,&in->variant.fileVariant, chunk);
2503 theChunk = tn->level0[chunk & YAFFS_TNODES_LEVEL0_MASK] << in->myDev->chunkGroupBits;
2505 if(yaffs_CheckChunkBits(dev,theChunk/dev->nChunksPerBlock,theChunk%dev->nChunksPerBlock))
2509 yaffs_ReadChunkTagsFromNAND(in->myDev,theChunk,tags,&chunkDeleted);
2510 if(yaffs_TagsMatch(tags,in->objectId,chunk,chunkDeleted))
2518 //T(("File problem file [%d,%d] NAND %d tags[%d,%d]\n",
2519 // objId,chunk,theChunk,tags->chunkId,tags->objectId);
2528 //T(("No level 0 found for %d\n", chunk));
2532 return failed ? YAFFS_FAIL : YAFFS_OK;
2537 static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan)
2539 // NB inScan is zero unless scanning. For forward scanning, inScan is > 0; for backward scanning inScan is < 0
2541 yaffs_Device *dev = in->myDev;
2543 yaffs_ExtendedTags existingTags;
2544 yaffs_ExtendedTags newTags;
2545 unsigned existingSerial, newSerial;
2547 if(in->variantType != YAFFS_OBJECT_TYPE_FILE)
2549 // Just ignore an attempt at putting a chunk into a non-file during scanning
2550 // If it is not during Scanning then something went wrong!
2553 T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy:attempt to put data chunk into a non-file" TENDSTR)));
2557 yaffs_DeleteChunk(dev,chunkInNAND,1,__LINE__);
2561 tn = yaffs_AddOrFindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
2567 existingChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK];
2571 // If we're scanning then we need to test for duplicates
2572 // NB This does not need to be efficient since it should only ever
2573 // happen when the power fails during a write, then only one
2574 // chunk should ever be affected.
2576 // Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
2577 // Update: For backward scanning we don't need to re-read tags so this is quite cheap.
2581 if(existingChunk != 0)
2583 // NB Right now existing chunk will not be real chunkId if the device >= 32MB
2584 // thus we have to do a FindChunkInFile to get the real chunk id.
2586 // We have a duplicate now we need to decide which one to use:
2588 // Backwards scanning YAFFS2: The old one is what we use, dump the new one.
2589 // Forward scanning YAFFS2: The new one is what we use, dump the old one.
2590 // YAFFS1: Get both sets of tags and compare serial numbers.
2596 // Only do this for forward scanning
2597 yaffs_ReadChunkWithTagsFromNAND(dev,chunkInNAND, NULL,&newTags);
2601 existingChunk = yaffs_FindChunkInFile(in,chunkInInode, &existingTags);
2604 if(existingChunk <=0)
2606 //Hoosterman - how did this happen?
2608 T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: existing chunk < 0 in scan" TENDSTR)));
2613 // NB The deleted flags should be false, otherwise the chunks will
2614 // not be loaded during a scan
2616 newSerial = newTags.serialNumber;
2617 existingSerial = existingTags.serialNumber;
2620 ( in->myDev->isYaffs2 ||
2621 existingChunk <= 0 ||
2622 ((existingSerial+1) & 3) == newSerial))
2624 // Forward scanning.
2626 // Delete the old one and drop through to update the tnode
2627 yaffs_DeleteChunk(dev,existingChunk,1,__LINE__);
2631 // Backward scanning or we want to use the existing one
2633 // Delete the new one and return early so that the tnode isn't changed
2634 yaffs_DeleteChunk(dev,chunkInNAND,1,__LINE__);
2641 if(existingChunk == 0)
2646 tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] = (chunkInNAND >> dev->chunkGroupBits);
2653 static int yaffs_ReadChunkDataFromObject(yaffs_Object *in,int chunkInInode, __u8 *buffer)
2655 int chunkInNAND = yaffs_FindChunkInFile(in,chunkInInode,NULL);
2657 if(chunkInNAND >= 0)
2659 return yaffs_ReadChunkWithTagsFromNAND(in->myDev,chunkInNAND,buffer,NULL);
2663 T(YAFFS_TRACE_NANDACCESS,(TSTR("Chunk %d not found zero instead" TENDSTR),chunkInNAND));
2665 memset(buffer,0,in->myDev->nBytesPerChunk); // get sane data if you read a hole
2672 void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId,int markNAND,int lyn)
2676 yaffs_ExtendedTags tags;
2677 yaffs_BlockInfo *bi;
2679 if(chunkId <= 0) return;
2682 block = chunkId / dev->nChunksPerBlock;
2683 page = chunkId % dev->nChunksPerBlock;
2685 bi = yaffs_GetBlockInfo(dev,block);
2687 T(YAFFS_TRACE_DELETION,(TSTR("line %d delete of chunk %d" TENDSTR),lyn,chunkId));
2690 bi->blockState != YAFFS_BLOCK_STATE_COLLECTING &&
2693 // yaffs_SpareInitialise(&spare);
2695 #ifdef CONFIG_MTD_NAND_VERIFY_WRITE
2697 //read data before write, to ensure correct ecc
2698 //if we're using MTD verification under Linux
2699 yaffs_ReadChunkFromNAND(dev,chunkId,NULL,&spare,0);
2702 yaffs_InitialiseTags(&tags);
2704 tags.chunkDeleted = 1;
2707 yaffs_WriteChunkWithTagsToNAND(dev,chunkId,NULL,&tags);
2708 yaffs_HandleUpdateChunk(dev,chunkId,&tags);
2712 dev->nUnmarkedDeletions++;
2716 // Pull out of the management area.
2717 // If the whole block became dirty, this will kick off an erasure.
2718 if( bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING ||
2719 bi->blockState == YAFFS_BLOCK_STATE_FULL ||
2720 bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
2721 bi->blockState == YAFFS_BLOCK_STATE_COLLECTING)
2725 yaffs_ClearChunkBit(dev,block,page);
2729 if(bi->pagesInUse == 0 &&
2730 !bi->hasShrinkHeader &&
2731 bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING &&
2732 bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING)
2734 yaffs_BlockBecameDirty(dev,block);
2740 // T(("Bad news deleting chunk %d\n",chunkId));
2748 static int yaffs_WriteChunkDataToObject(yaffs_Object *in,int chunkInInode, const __u8 *buffer,int nBytes,int useReserve)
2750 // Find old chunk Need to do this to get serial number
2751 // Write new one and patch into tree.
2752 // Invalidate old tags.
2755 yaffs_ExtendedTags prevTags;
2758 yaffs_ExtendedTags newTags;
2760 yaffs_Device *dev = in->myDev;
2762 yaffs_CheckGarbageCollection(dev);
2764 // Get the previous chunk at this location in the file if it exists
2765 prevChunkId = yaffs_FindChunkInFile(in,chunkInInode,&prevTags);
2768 yaffs_InitialiseTags(&newTags);
2770 newTags.chunkId = chunkInInode;
2771 newTags.objectId = in->objectId;
2772 newTags.serialNumber = (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1;
2773 newTags.byteCount = nBytes;
2775 // yaffs_CalcTagsECC(&newTags);
2777 newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,buffer,&newTags,useReserve);
2781 yaffs_PutChunkIntoFile(in,chunkInInode,newChunkId,0);
2784 if(prevChunkId >= 0)
2786 yaffs_DeleteChunk(dev,prevChunkId,1,__LINE__);
2790 yaffs_CheckFileSanity(in);
2801 // UpdateObjectHeader updates the header on NAND for an object.
2802 // If name is not NULL, then that new name is used.
2804 int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int isShrink,int shadows)
2807 yaffs_BlockInfo *bi;
2809 yaffs_Device *dev = in->myDev;
2815 yaffs_ExtendedTags newTags;
2817 __u8 *buffer = NULL;
2818 YCHAR oldName[YAFFS_MAX_NAME_LENGTH+1];
2820 // __u8 bufferOld[YAFFS_BYTES_PER_CHUNK];
2822 yaffs_ObjectHeader *oh = NULL;
2823 // yaffs_ObjectHeader *ohOld = (yaffs_ObjectHeader *)bufferOld;
2826 if(!in->fake || force)
2829 yaffs_CheckGarbageCollection(dev);
2831 buffer = yaffs_GetTempBuffer(in->myDev,__LINE__);
2832 oh = (yaffs_ObjectHeader *)buffer;
2834 prevChunkId = in->chunkId;
2836 if(prevChunkId >= 0)
2838 yaffs_ReadChunkWithTagsFromNAND(dev,prevChunkId,buffer,NULL);
2839 memcpy(oldName,oh->name,sizeof(oh->name));
2842 memset(buffer,0xFF,dev->nBytesPerChunk);
2845 oh->type = in->variantType;
2847 oh->yst_mode = in->yst_mode;
2850 oh->shadowsObject = shadows;
2852 #ifdef CONFIG_YAFFS_WINCE
2853 oh->win_atime[0] = in->win_atime[0];
2854 oh->win_ctime[0] = in->win_ctime[0];
2855 oh->win_mtime[0] = in->win_mtime[0];
2856 oh->win_atime[1] = in->win_atime[1];
2857 oh->win_ctime[1] = in->win_ctime[1];
2858 oh->win_mtime[1] = in->win_mtime[1];
2860 oh->yst_uid = in->yst_uid;
2861 oh->yst_gid = in->yst_gid;
2862 oh->yst_atime = in->yst_atime;
2863 oh->yst_mtime = in->yst_mtime;
2864 oh->yst_ctime = in->yst_ctime;
2865 oh->yst_rdev = in->yst_rdev;
2869 oh->parentObjectId = in->parent->objectId;
2873 oh->parentObjectId = 0;
2876 //oh->sum = in->sum;
2879 memset(oh->name,0,sizeof(oh->name));
2880 yaffs_strncpy(oh->name,name,YAFFS_MAX_NAME_LENGTH);
2882 else if(prevChunkId)
2884 memcpy(oh->name, oldName,sizeof(oh->name));
2888 memset(oh->name,0,sizeof(oh->name));
2891 oh->isShrink = isShrink;
2893 switch(in->variantType)
2895 case YAFFS_OBJECT_TYPE_UNKNOWN:
2896 // Should not happen
2898 case YAFFS_OBJECT_TYPE_FILE:
2899 oh->fileSize = (oh->parentObjectId == YAFFS_OBJECTID_DELETED ||
2900 oh->parentObjectId == YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant.fileVariant.fileSize;
2902 case YAFFS_OBJECT_TYPE_HARDLINK:
2903 oh->equivalentObjectId = in->variant.hardLinkVariant.equivalentObjectId;
2905 case YAFFS_OBJECT_TYPE_SPECIAL:
2908 case YAFFS_OBJECT_TYPE_DIRECTORY:
2911 case YAFFS_OBJECT_TYPE_SYMLINK:
2912 yaffs_strncpy(oh->alias,in->variant.symLinkVariant.alias,YAFFS_MAX_ALIAS_LENGTH);
2913 oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
2918 yaffs_InitialiseTags(&newTags);
2920 newTags.chunkId = 0;
2921 newTags.objectId = in->objectId;
2922 newTags.serialNumber = in->serial;
2924 // Add extra info for file header
2926 newTags.extraHeaderInfoAvailable = 1;
2927 newTags.extraParentObjectId = oh->parentObjectId;
2928 newTags.extraFileLength = oh->fileSize;
2929 newTags.extraIsShrinkHeader = oh->isShrink;
2930 newTags.extraEquivalentObjectId = oh->equivalentObjectId;
2931 newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0;
2932 newTags.extraObjectType = in->variantType;
2934 // Create new chunk in NAND
2935 newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,buffer,&newTags, (prevChunkId >= 0) ? 1 : 0 );
2940 in->chunkId = newChunkId;
2942 if(prevChunkId >= 0)
2944 yaffs_DeleteChunk(dev,prevChunkId,1,__LINE__);
2949 // If this was a shrink, then mark the block that the chunk lives on
2952 bi = yaffs_GetBlockInfo(in->myDev,newChunkId / in->myDev->nChunksPerBlock);
2953 bi->hasShrinkHeader = 1;
2958 retVal = newChunkId;
2963 yaffs_ReleaseTempBuffer(dev,buffer,__LINE__);
2969 /////////////////////// Short Operations Cache ////////////////////////////////
2970 // In many siturations where there is no high level buffering (eg WinCE) a lot of
2971 // reads might be short sequential reads, and a lot of writes may be short
2972 // sequential writes. eg. scanning/writing a jpeg file.
2973 // In these cases, a short read/write cache can provide a huge perfomance benefit
2974 // with dumb-as-a-rock code.
2975 // There are a limited number (~10) of cache chunks per device so that we don't
2976 // need a very intelligent search.
2982 static void yaffs_FlushFilesChunkCache(yaffs_Object *obj)
2984 yaffs_Device *dev = obj->myDev;
2985 int lowest = -99; // Stop compiler whining.
2987 yaffs_ChunkCache *cache;
2988 int chunkWritten = 0;
2990 int nCaches = obj->myDev->nShortOpCaches;
2997 // Find the dirty cache for this object with the lowest chunk id.
2998 for(i = 0; i < nCaches; i++)
3000 if(dev->srCache[i].object == obj &&
3001 dev->srCache[i].dirty)
3003 if(!cache || dev->srCache[i].chunkId < lowest)
3005 cache = &dev->srCache[i];
3006 lowest = cache->chunkId;
3011 if(cache && !cache->locked)
3013 //Write it out and free it up
3015 chunkWritten = yaffs_WriteChunkDataToObject(cache->object,
3020 cache->object = NULL;
3023 } while(cache && chunkWritten > 0);
3027 //Hoosterman, disk full while writing cache out.
3028 T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: no space during cache write" TENDSTR)));
3036 // Grab us a chunk for use.
3037 // First look for an empty one.
3038 // Then look for the least recently used non-dirty one.
3039 // Then look for the least recently used dirty one...., flush and look again.
3040 static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev)
3046 if(dev->nShortOpCaches > 0)
3048 for(i = 0; i < dev->nShortOpCaches; i++)
3050 if(!dev->srCache[i].object)
3052 //T(("Grabbing empty %d\n",i));
3054 //printf("Grabbing empty %d\n",i);
3056 return &dev->srCache[i];
3063 usage = 0; // just to stop the compiler grizzling
3065 for(i = 0; i < dev->nShortOpCaches; i++)
3067 if(!dev->srCache[i].dirty &&
3068 ((dev->srCache[i].lastUse < usage && theOne >= 0)||
3071 usage = dev->srCache[i].lastUse;
3076 //T(("Grabbing non-empty %d\n",theOne));
3078 //if(theOne >= 0) printf("Grabbed non-empty cache %d\n",theOne);
3080 return theOne >= 0 ? &dev->srCache[theOne] : NULL;
3090 static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev)
3092 yaffs_ChunkCache *cache;
3093 yaffs_Object *theObj;
3098 if(dev->nShortOpCaches > 0)
3100 // Try find a non-dirty one...
3102 cache = yaffs_GrabChunkCacheWorker(dev);
3106 // They were all dirty, find the last recently used object and flush
3107 // its cache, then find again.
3108 // NB what's here is not very accurate, we actually flush the object
3109 // the last recently used page.
3111 // With locking we can't assume we can use entry zero
3119 for(i = 0; i < dev->nShortOpCaches; i++)
3121 if( dev->srCache[i].object &&
3122 !dev->srCache[i].locked &&
3123 (dev->srCache[i].lastUse < usage || !cache))
3125 usage = dev->srCache[i].lastUse;
3126 theObj = dev->srCache[i].object;
3127 cache = &dev->srCache[i];
3132 if(!cache || cache->dirty)
3136 yaffs_FlushFilesChunkCache(theObj);
3139 cache = yaffs_GrabChunkCacheWorker(dev);
3143 //printf(" pushout %d\n",pushout);
3155 // Find a cached chunk
3156 static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object *obj, int chunkId)
3158 yaffs_Device *dev = obj->myDev;
3160 if(dev->nShortOpCaches > 0)
3162 for(i = 0; i < dev->nShortOpCaches; i++)
3164 if(dev->srCache[i].object == obj &&
3165 dev->srCache[i].chunkId == chunkId)
3169 return &dev->srCache[i];
3176 // Mark the chunk for the least recently used algorithym
3177 static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache, int isAWrite)
3180 if(dev->nShortOpCaches > 0)
3182 if( dev->srLastUse < 0 ||
3183 dev->srLastUse > 100000000)
3185 // Reset the cache usages
3187 for(i = 1; i < dev->nShortOpCaches; i++)
3189 dev->srCache[i].lastUse = 0;
3196 cache->lastUse = dev->srLastUse;
3205 // Invalidate a single cache page.
3206 // Do this when a whole page gets written,
3207 // ie the short cache for this page is no longer valid.
3208 static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId)
3210 if(object->myDev->nShortOpCaches > 0)
3212 yaffs_ChunkCache *cache = yaffs_FindChunkCache(object,chunkId);
3216 cache->object = NULL;
3222 // Invalidate all the cache pages associated with this object
3223 // Do this whenever ther file is deleted or resized.
3224 static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in)
3227 yaffs_Device *dev = in->myDev;
3229 if(dev->nShortOpCaches > 0)
3231 // Now invalidate it.
3232 for(i = 0; i < dev->nShortOpCaches; i++)
3234 if(dev->srCache[i].object == in)
3236 dev->srCache[i].object = NULL;
3246 ///////////////////////// File read/write ///////////////////////////////
3247 // Read and write have very similar structures.
3248 // In general the read/write has three parts to it
3249 // * An incomplete chunk to start with (if the read/write is not chunk-aligned)
3250 // * Some complete chunks
3251 // * An incomplete chunk to end off with
3253 // Curve-balls: the first chunk might also be the last chunk.
3255 int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 * buffer, __u32 offset, int nBytes)
3264 yaffs_ChunkCache *cache;
3272 chunk = offset / dev->nBytesPerChunk + 1; // The first chunk is 1
3273 start = offset % dev->nBytesPerChunk;
3275 // OK now check for the curveball where the start and end are in
3277 if( (start + n) < dev->nBytesPerChunk)
3283 nToCopy = dev->nBytesPerChunk - start;
3286 cache = yaffs_FindChunkCache(in,chunk);
3288 // If the chunk is already in the cache or it is less than a whole chunk
3289 // then use the cache (if there is caching)
3290 // else bypass the cache.
3291 if( cache || nToCopy != dev->nBytesPerChunk)
3293 if(dev->nShortOpCaches > 0)
3296 // If we can't find the data in the cache, then load it up.
3300 cache = yaffs_GrabChunkCache(in->myDev);
3302 cache->chunkId = chunk;
3305 yaffs_ReadChunkDataFromObject(in,chunk,cache->data);
3309 yaffs_UseChunkCache(dev,cache,0);
3313 #ifdef CONFIG_YAFFS_WINCE
3314 yfsd_UnlockYAFFS(TRUE);
3316 memcpy(buffer,&cache->data[start],nToCopy);
3318 #ifdef CONFIG_YAFFS_WINCE
3319 yfsd_LockYAFFS(TRUE);
3325 // Read into the local buffer then copy...
3327 __u8 *localBuffer = yaffs_GetTempBuffer(dev,__LINE__);
3328 yaffs_ReadChunkDataFromObject(in,chunk,localBuffer);
3329 #ifdef CONFIG_YAFFS_WINCE
3330 yfsd_UnlockYAFFS(TRUE);
3332 memcpy(buffer,&localBuffer[start],nToCopy);
3334 #ifdef CONFIG_YAFFS_WINCE
3335 yfsd_LockYAFFS(TRUE);
3337 yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
3343 #ifdef CONFIG_YAFFS_WINCE
3344 __u8 *localBuffer = yaffs_GetTempBuffer(dev,__LINE__);
3346 // Under WinCE can't do direct transfer. Need to use a local buffer.
3347 // This is because we otherwise screw up WinCE's memory mapper
3348 yaffs_ReadChunkDataFromObject(in,chunk,localBuffer);
3350 #ifdef CONFIG_YAFFS_WINCE
3351 yfsd_UnlockYAFFS(TRUE);
3353 memcpy(buffer,localBuffer,dev->nBytesPerChunk);
3355 #ifdef CONFIG_YAFFS_WINCE
3356 yfsd_LockYAFFS(TRUE);
3357 yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
3361 // A full chunk. Read directly into the supplied buffer.
3362 yaffs_ReadChunkDataFromObject(in,chunk,buffer);
3378 int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, int nBytes, int writeThrough)
3387 int startOfWrite = offset;
3388 int chunkWritten = 0;
3396 while(n > 0 && chunkWritten >= 0)
3398 chunk = offset / dev->nBytesPerChunk + 1;
3399 start = offset % dev->nBytesPerChunk;
3402 // OK now check for the curveball where the start and end are in
3405 if((start + n) < dev->nBytesPerChunk)
3409 // Now folks, to calculate how many bytes to write back....
3410 // If we're overwriting and not writing to then end of file then
3411 // we need to write back as much as was there before.
3413 nBytesRead = in->variant.fileVariant.fileSize - ((chunk -1) * dev->nBytesPerChunk);
3415 if(nBytesRead > dev->nBytesPerChunk)
3417 nBytesRead = dev->nBytesPerChunk;
3420 nToWriteBack = (nBytesRead > (start + n)) ? nBytesRead : (start +n);
3425 nToCopy = dev->nBytesPerChunk - start;
3426 nToWriteBack = dev->nBytesPerChunk;
3429 if(nToCopy != dev->nBytesPerChunk)
3431 // An incomplete start or end chunk (or maybe both start and end chunk)
3432 if(dev->nShortOpCaches > 0)
3434 yaffs_ChunkCache *cache;
3435 // If we can't find the data in the cache, then load it up.
3436 cache = yaffs_FindChunkCache(in,chunk);
3437 if(!cache && yaffs_CheckSpaceForAllocation(in->myDev))
3439 cache = yaffs_GrabChunkCache(in->myDev);
3441 cache->chunkId = chunk;
3444 yaffs_ReadChunkDataFromObject(in,chunk,cache->data);
3449 yaffs_UseChunkCache(dev,cache,1);
3451 #ifdef CONFIG_YAFFS_WINCE
3452 yfsd_UnlockYAFFS(TRUE);
3455 memcpy(&cache->data[start],buffer,nToCopy);
3457 #ifdef CONFIG_YAFFS_WINCE
3458 yfsd_LockYAFFS(TRUE);
3461 cache->nBytes = nToWriteBack;
3465 chunkWritten = yaffs_WriteChunkDataToObject(cache->object,
3475 chunkWritten = -1; // fail the write
3480 // An incomplete start or end chunk (or maybe both start and end chunk)
3481 // Read into the local buffer then copy, then copy over and write back.
3483 __u8 *localBuffer = yaffs_GetTempBuffer(dev,__LINE__);
3485 yaffs_ReadChunkDataFromObject(in,chunk,localBuffer);
3487 #ifdef CONFIG_YAFFS_WINCE
3488 yfsd_UnlockYAFFS(TRUE);
3491 memcpy(&localBuffer[start],buffer,nToCopy);
3493 #ifdef CONFIG_YAFFS_WINCE
3494 yfsd_LockYAFFS(TRUE);
3496 chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,localBuffer,nToWriteBack,0);
3498 yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
3500 //T(("Write with readback to chunk %d %d start %d copied %d wrote back %d\n",chunk,chunkWritten,start, nToCopy, nToWriteBack));
3507 #ifdef CONFIG_YAFFS_WINCE
3508 // Under WinCE can't do direct transfer. Need to use a local buffer.
3509 // This is because we otherwise screw up WinCE's memory mapper
3510 __u8 *localBuffer = yaffs_GetTempBuffer(dev,__LINE__);
3511 #ifdef CONFIG_YAFFS_WINCE
3512 yfsd_UnlockYAFFS(TRUE);
3514 memcpy(localBuffer,buffer,dev->nBytesPerChunk);
3515 #ifdef CONFIG_YAFFS_WINCE
3516 yfsd_LockYAFFS(TRUE);
3518 chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,localBuffer,dev->nBytesPerChunk,0);
3519 yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
3521 // A full chunk. Write directly from the supplied buffer.
3522 chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,buffer,dev->nBytesPerChunk,0);
3524 // Since we've overwritten the cached data, we better invalidate it.
3525 yaffs_InvalidateChunkCache(in,chunk);
3526 //T(("Write to chunk %d %d\n",chunk,chunkWritten));
3529 if(chunkWritten >= 0)
3539 // Update file object
3541 if((startOfWrite + nDone) > in->variant.fileVariant.fileSize)
3543 in->variant.fileVariant.fileSize = (startOfWrite + nDone);
3551 static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize)
3554 yaffs_Device *dev = in->myDev;
3555 int oldFileSize = in->variant.fileVariant.fileSize;
3558 int lastDel = 1 + (oldFileSize-1)/dev->nBytesPerChunk;
3560 int startDel = 1 + (newSize + dev->nBytesPerChunk - 1)/
3561 dev->nBytesPerChunk;
3565 // Delete backwards so that we don't end up with holes if
3566 // power is lost part-way through the operation.
3567 for(i = lastDel; i >= startDel; i--)
3569 // NB this could be optimised somewhat,
3570 // eg. could retrieve the tags and write them without
3571 // using yaffs_DeleteChunk
3573 chunkId = yaffs_FindAndDeleteChunkInFile(in,i,NULL);
3576 if(chunkId < (dev->internalStartBlock * dev->nChunksPerBlock) ||
3577 chunkId >= ((dev->internalEndBlock+1) * dev->nChunksPerBlock))
3579 T(YAFFS_TRACE_ALWAYS,(TSTR("Found daft chunkId %d for %d"TENDSTR),chunkId,i));
3584 yaffs_DeleteChunk(dev,chunkId,1,__LINE__);
3591 int yaffs_ResizeFile(yaffs_Object *in, int newSize)
3594 int oldFileSize = in->variant.fileVariant.fileSize;
3595 int sizeOfPartialChunk;
3596 yaffs_Device *dev = in->myDev;
3598 sizeOfPartialChunk = newSize % dev->nBytesPerChunk;
3601 yaffs_FlushFilesChunkCache(in);
3602 yaffs_InvalidateWholeChunkCache(in);
3604 yaffs_CheckGarbageCollection(dev);
3606 if(in->variantType != YAFFS_OBJECT_TYPE_FILE)
3608 return yaffs_GetFileSize(in);
3611 if(newSize == oldFileSize)
3616 if(newSize < oldFileSize)
3619 yaffs_PruneResizedChunks(in,newSize);
3621 if(sizeOfPartialChunk != 0)
3623 int lastChunk = 1+ newSize/dev->nBytesPerChunk;
3624 __u8 *localBuffer = yaffs_GetTempBuffer(dev,__LINE__);
3626 // Got to read and rewrite the last chunk with its new size and zero pad
3627 yaffs_ReadChunkDataFromObject(in,lastChunk,localBuffer);
3629 memset(localBuffer + sizeOfPartialChunk,0, dev->nBytesPerChunk - sizeOfPartialChunk);
3631 yaffs_WriteChunkDataToObject(in,lastChunk,localBuffer,sizeOfPartialChunk,1);
3633 yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
3636 in->variant.fileVariant.fileSize = newSize;
3638 yaffs_PruneFileStructure(dev,&in->variant.fileVariant);
3641 // Write a new object header.
3642 // show we've shrunk the file, if need be
3643 // Do this only if the file is not in the deleted directories.
3644 if(in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
3645 in->parent->objectId != YAFFS_OBJECTID_DELETED
3648 yaffs_UpdateObjectHeader(in,NULL, 0, (newSize < oldFileSize) ? 1 : 0 ,0);
3656 loff_t yaffs_GetFileSize(yaffs_Object *obj)
3658 obj = yaffs_GetEquivalentObject(obj);
3660 switch(obj->variantType)
3662 case YAFFS_OBJECT_TYPE_FILE:
3663 return obj->variant.fileVariant.fileSize;
3664 case YAFFS_OBJECT_TYPE_SYMLINK:
3665 return yaffs_strlen(obj->variant.symLinkVariant.alias);
3673 // yaffs_FlushFile() updates the file's
3676 int yaffs_FlushFile(yaffs_Object *in, int updateTime)
3681 //T(("flushing object header\n"));
3683 yaffs_FlushFilesChunkCache(in);
3686 #ifdef CONFIG_YAFFS_WINCE
3687 yfsd_WinFileTimeNow(in->win_mtime);
3690 in->yst_mtime = Y_CURRENT_TIME;
3695 retVal = (yaffs_UpdateObjectHeader(in,NULL,0,0,0) >= 0)? YAFFS_OK : YAFFS_FAIL;
3707 static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
3710 // First off, invalidate the file's data in the cache, without flushing.
3711 yaffs_InvalidateWholeChunkCache(in);
3713 if(in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir))
3715 // Move to the unlinked directory so we have a record that it was deleted.
3716 yaffs_ChangeObjectName(in, in->myDev->deletedDir,NULL,0,0);
3721 yaffs_RemoveObjectFromDirectory(in);
3722 yaffs_DeleteChunk(in->myDev,in->chunkId,1,__LINE__);
3725 yaffs_FreeObject(in);
3730 // yaffs_DeleteFile deletes the whole file data
3731 // and the inode associated with the file.
3732 // It does not delete the links associated with the file.
3733 static int yaffs_UnlinkFile(yaffs_Object *in)
3738 int immediateDeletion=0;
3743 //in->myDev->nUnlinkedFiles++;
3744 //in->renameAllowed = 0;
3748 immediateDeletion = 1;
3754 immediateDeletion = 1;
3758 if(immediateDeletion)
3760 retVal = yaffs_ChangeObjectName(in, in->myDev->deletedDir,NULL,0,0);
3761 T(YAFFS_TRACE_TRACING,(TSTR("yaffs: immediate deletion of file %d" TENDSTR),in->objectId));
3763 in->myDev->nDeletedFiles++;
3764 if( 0 && in->myDev->isYaffs2)
3766 yaffs_ResizeFile(in,0);
3768 yaffs_SoftDeleteFile(in);
3772 retVal = yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,NULL,0,0);
3779 int yaffs_DeleteFile(yaffs_Object *in)
3781 int retVal = YAFFS_OK;
3783 if(in->nDataChunks > 0)
3785 // Use soft deletion
3788 retVal = yaffs_UnlinkFile(in);
3790 if(retVal == YAFFS_OK &&
3795 in->myDev->nDeletedFiles++;
3796 yaffs_SoftDeleteFile(in);
3798 return in->deleted ? YAFFS_OK : YAFFS_FAIL;
3802 // The file has no data chunks so we toss it immediately
3803 yaffs_FreeTnode(in->myDev,in->variant.fileVariant.top);
3804 in->variant.fileVariant.top = NULL;
3805 yaffs_DoGenericObjectDeletion(in);
3811 static int yaffs_DeleteDirectory(yaffs_Object *in)
3813 //First check that the directory is empty.
3814 if(list_empty(&in->variant.directoryVariant.children))
3816 return yaffs_DoGenericObjectDeletion(in);
3823 static int yaffs_DeleteSymLink(yaffs_Object *in)
3825 YFREE(in->variant.symLinkVariant.alias);
3827 return yaffs_DoGenericObjectDeletion(in);
3830 static int yaffs_DeleteHardLink(yaffs_Object *in)
3832 // remove this hardlink from the list assocaited with the equivalent
3834 list_del(&in->hardLinks);
3835 return yaffs_DoGenericObjectDeletion(in);
3839 static void yaffs_DestroyObject(yaffs_Object *obj)
3841 switch(obj->variantType)
3843 case YAFFS_OBJECT_TYPE_FILE: yaffs_DeleteFile(obj); break;
3844 case YAFFS_OBJECT_TYPE_DIRECTORY: yaffs_DeleteDirectory(obj); break;
3845 case YAFFS_OBJECT_TYPE_SYMLINK: yaffs_DeleteSymLink(obj); break;
3846 case YAFFS_OBJECT_TYPE_HARDLINK: yaffs_DeleteHardLink(obj); break;
3847 case YAFFS_OBJECT_TYPE_SPECIAL: yaffs_DoGenericObjectDeletion(obj); break;
3848 case YAFFS_OBJECT_TYPE_UNKNOWN: break; // should not happen.
3853 static int yaffs_UnlinkWorker(yaffs_Object *obj)
3857 if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
3859 return yaffs_DeleteHardLink(obj);
3861 else if(!list_empty(&obj->hardLinks))
3863 // Curve ball: We're unlinking an object that has a hardlink.
3865 // This problem arises because we are not strictly following
3866 // The Linux link/inode model.
3868 // We can't really delete the object.
3869 // Instead, we do the following:
3870 // - Select a hardlink.
3871 // - Unhook it from the hard links
3872 // - Unhook it from its parent directory (so that the rename can work)
3873 // - Rename the object to the hardlink's name.
3874 // - Delete the hardlink
3879 YCHAR name[YAFFS_MAX_NAME_LENGTH+1];
3881 hl = list_entry(obj->hardLinks.next,yaffs_Object,hardLinks);
3883 list_del_init(&hl->hardLinks);
3884 list_del_init(&hl->siblings);
3886 yaffs_GetObjectName(hl,name,YAFFS_MAX_NAME_LENGTH+1);
3888 retVal = yaffs_ChangeObjectName(obj, hl->parent, name,0,0);
3890 if(retVal == YAFFS_OK)
3892 retVal = yaffs_DoGenericObjectDeletion(hl);
3899 switch(obj->variantType)
3901 case YAFFS_OBJECT_TYPE_FILE:
3902 return yaffs_UnlinkFile(obj);
3904 case YAFFS_OBJECT_TYPE_DIRECTORY:
3905 return yaffs_DeleteDirectory(obj);
3907 case YAFFS_OBJECT_TYPE_SYMLINK:
3908 return yaffs_DeleteSymLink(obj);
3910 case YAFFS_OBJECT_TYPE_SPECIAL:
3911 return yaffs_DoGenericObjectDeletion(obj);
3913 case YAFFS_OBJECT_TYPE_HARDLINK:
3914 case YAFFS_OBJECT_TYPE_UNKNOWN:
3921 int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name)
3925 obj = yaffs_FindObjectByName(dir,name);
3927 if(obj && obj->unlinkAllowed)
3929 return yaffs_UnlinkWorker(obj);
3936 //////////////// Initialisation Scanning /////////////////
3939 static void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId, int backwardScanning)
3943 if(!backwardScanning)
3945 // Handle YAFFS1 forward scanning case
3946 // For YAFFS1 we always do the deletion
3950 { // Handle YAFFS2 case (backward scanning)
3951 // If the shadowed object exists then ignore.
3952 if(yaffs_FindObjectByNumber(dev,objId))
3958 // Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc.
3959 // We put it in unlinked dir to be cleaned up after the scanning
3960 obj = yaffs_FindOrCreateObjectByNumber(dev,objId,YAFFS_OBJECT_TYPE_FILE);
3961 yaffs_AddObjectToDirectory(dev->unlinkedDir,obj);
3962 obj->variant.fileVariant.shrinkSize = 0;
3963 obj->valid = 1; // So that we don't read any other infor for this file
3978 static int yaffs_Scan(yaffs_Device *dev)
3980 yaffs_ExtendedTags tags;
3985 int nBlocksToScan = 0;
3990 yaffs_BlockState state;
3991 yaffs_Object *hardList = NULL;
3993 yaffs_BlockInfo *bi;
3995 yaffs_ObjectHeader *oh;
3997 yaffs_Object *parent;
3998 int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
4002 yaffs_BlockIndex *blockIndex = NULL;
4004 T(YAFFS_TRACE_SCAN,(TSTR("yaffs_Scan starts intstartblk %d intendblk %d..." TENDSTR),dev->internalStartBlock,dev->internalEndBlock));
4006 chunkData = yaffs_GetTempBuffer(dev,__LINE__);
4009 dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
4013 blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
4017 // Scan all the blocks to determine their state
4018 for(blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++)
4020 bi = yaffs_GetBlockInfo(dev,blk);
4021 yaffs_ClearChunkBits(dev,blk);
4023 bi->softDeletions = 0;
4025 yaffs_QueryInitialBlockState(dev,blk,&state,&sequenceNumber);
4027 bi->blockState = state;
4028 bi->sequenceNumber = sequenceNumber;
4030 T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("Block scanning block %d state %d seq %d" TENDSTR),blk,state,sequenceNumber));
4032 if(state == YAFFS_BLOCK_STATE_DEAD)
4034 T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("block %d is bad" TENDSTR),blk));
4036 else if(state == YAFFS_BLOCK_STATE_EMPTY)
4038 T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("Block empty " TENDSTR)));
4039 dev->nErasedBlocks++;
4040 dev->nFreeChunks += dev->nChunksPerBlock;
4042 else if(state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
4045 // Determine the highest sequence number
4046 if( dev->isYaffs2 &&
4047 sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
4048 sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER)
4051 blockIndex[nBlocksToScan].seq = sequenceNumber;
4052 blockIndex[nBlocksToScan].block = blk;
4056 if(sequenceNumber >= dev->sequenceNumber)
4058 dev->sequenceNumber = sequenceNumber;
4061 else if(dev->isYaffs2)
4063 // TODO: Nasty sequence number!
4064 T(YAFFS_TRACE_SCAN,(TSTR("Block scanning block %d has bad sequence number %d" TENDSTR),blk,sequenceNumber));
4071 // Dungy old bubble sort for now...
4074 yaffs_BlockIndex temp;
4078 for(i = 0; i < nBlocksToScan; i++)
4079 for(j = i+1; j < nBlocksToScan; j++)
4080 if(blockIndex[i].seq > blockIndex[j].seq)
4082 temp = blockIndex[j];
4083 blockIndex[j] = blockIndex[i];
4084 blockIndex[i] = temp;
4089 // Now scan the blocks looking at the data.
4093 endIterator = nBlocksToScan-1;
4094 T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("%d blocks to be scanned" TENDSTR),nBlocksToScan));
4098 startIterator = dev->internalStartBlock;
4099 endIterator = dev->internalEndBlock;
4102 // For each block....
4103 for(blockIterator = startIterator; blockIterator <= endIterator; blockIterator++)
4108 // get the block to scan in the correct order
4109 blk = blockIndex[blockIterator].block;
4113 blk = blockIterator;
4117 bi = yaffs_GetBlockInfo(dev,blk);
4118 state = bi->blockState;
4122 // For each chunk in each block that needs scanning....
4123 for(c = 0; c < dev->nChunksPerBlock &&
4124 state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++)
4126 // Read the tags and decide what to do
4127 chunk = blk * dev->nChunksPerBlock + c;
4129 yaffs_ReadChunkWithTagsFromNAND(dev,chunk,NULL,&tags);
4131 // Let's have a good look at this chunk...
4134 if(!dev->isYaffs2 && tags.chunkDeleted)
4139 dev->nFreeChunks ++;
4140 //T((" %d %d deleted\n",blk,c));
4142 else if(!tags.chunkUsed)
4144 // An unassigned chunk in the block
4145 // This means that either the block is empty or
4146 // this is the one being allocated from
4150 // We're looking at the first chunk in the block so the block is unused
4151 state = YAFFS_BLOCK_STATE_EMPTY;
4152 dev->nErasedBlocks++;
4156 // this is the block being allocated from
4157 T(YAFFS_TRACE_SCAN,(TSTR(" Allocating from %d %d" TENDSTR),blk,c));
4158 state = YAFFS_BLOCK_STATE_ALLOCATING;
4159 dev->allocationBlock = blk;
4160 dev->allocationPage = c;
4161 dev->allocationBlockFinder = blk; // Set it to here to encourage the allocator to
4162 // go forth from here.
4163 //Yaffs2 sanity check:
4164 // This should be the one with the highest sequence number
4165 if(dev->isYaffs2 && (dev->sequenceNumber != bi->sequenceNumber))
4167 T(YAFFS_TRACE_ALWAYS,
4168 (TSTR("yaffs: Allocation block %d was not highest sequence id: block seq = %d, dev seq = %d" TENDSTR),
4169 blk,bi->sequenceNumber,dev->sequenceNumber));
4173 dev->nFreeChunks += (dev->nChunksPerBlock - c);
4175 else if(tags.chunkId > 0)
4177 // chunkId > 0 so it is a data chunk...
4178 unsigned int endpos;
4180 yaffs_SetChunkBit(dev,blk,c);
4183 in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,YAFFS_OBJECT_TYPE_FILE);
4184 // PutChunkIntoFile checks for a clash (two data chunks with
4185 // the same chunkId).
4186 yaffs_PutChunkIntoFile(in,tags.chunkId,chunk,1);
4187 endpos = (tags.chunkId - 1)* dev->nBytesPerChunk + tags.byteCount;
4188 if(in->variantType == YAFFS_OBJECT_TYPE_FILE && in->variant.fileVariant.scannedFileSize <endpos)
4190 in->variant.fileVariant.scannedFileSize = endpos;
4191 if(!dev->useHeaderFileSize)
4193 in->variant.fileVariant.fileSize = in->variant.fileVariant.scannedFileSize;
4197 //T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId));
4201 // chunkId == 0, so it is an ObjectHeader.
4202 // Thus, we read in the object header and make the object
4203 yaffs_SetChunkBit(dev,blk,c);
4206 yaffs_ReadChunkWithTagsFromNAND(dev,chunk,chunkData,NULL);
4208 oh = (yaffs_ObjectHeader *)chunkData;
4210 in = yaffs_FindObjectByNumber(dev,tags.objectId);
4211 if(in && in->variantType != oh->type)
4213 // This should not happen, but somehow
4214 // Wev'e ended up with an objectId that has been reused but not yet
4215 // deleted, and worse still it has changed type. Delete the old object.
4217 yaffs_DestroyObject(in);
4222 in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,oh->type);
4224 if(oh->shadowsObject > 0)
4226 yaffs_HandleShadowedObject(dev,oh->shadowsObject,0);
4231 // We have already filled this one. We have a duplicate and need to resolve it.
4233 unsigned existingSerial = in->serial;
4234 unsigned newSerial = tags.serialNumber;
4236 if( dev->isYaffs2 ||
4237 ((existingSerial+1) & 3) == newSerial)
4239 // Use new one - destroy the exisiting one
4240 yaffs_DeleteChunk(dev,in->chunkId,1,__LINE__);
4245 // Use existing - destroy this one.
4246 yaffs_DeleteChunk(dev,chunk,1,__LINE__);
4251 (tags.objectId == YAFFS_OBJECTID_ROOT ||
4252 tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))
4254 // We only load some info, don't fiddle with directory structure
4256 in->variantType = oh->type;
4258 in->yst_mode = oh->yst_mode;
4259 #ifdef CONFIG_YAFFS_WINCE
4260 in->win_atime[0] = oh->win_atime[0];
4261 in->win_ctime[0] = oh->win_ctime[0];
4262 in->win_mtime[0] = oh->win_mtime[0];
4263 in->win_atime[1] = oh->win_atime[1];
4264 in->win_ctime[1] = oh->win_ctime[1];
4265 in->win_mtime[1] = oh->win_mtime[1];
4267 in->yst_uid = oh->yst_uid;
4268 in->yst_gid = oh->yst_gid;
4269 in->yst_atime = oh->yst_atime;
4270 in->yst_mtime = oh->yst_mtime;
4271 in->yst_ctime = oh->yst_ctime;
4272 in->yst_rdev = oh->yst_rdev;
4274 in->chunkId = chunk;
4279 // we need to load this info
4282 in->variantType = oh->type;
4284 in->yst_mode = oh->yst_mode;
4285 #ifdef CONFIG_YAFFS_WINCE
4286 in->win_atime[0] = oh->win_atime[0];
4287 in->win_ctime[0] = oh->win_ctime[0];
4288 in->win_mtime[0] = oh->win_mtime[0];
4289 in->win_atime[1] = oh->win_atime[1];
4290 in->win_ctime[1] = oh->win_ctime[1];
4291 in->win_mtime[1] = oh->win_mtime[1];
4293 in->yst_uid = oh->yst_uid;
4294 in->yst_gid = oh->yst_gid;
4295 in->yst_atime = oh->yst_atime;
4296 in->yst_mtime = oh->yst_mtime;
4297 in->yst_ctime = oh->yst_ctime;
4298 in->yst_rdev = oh->yst_rdev;
4300 in->chunkId = chunk;
4302 yaffs_SetObjectName(in,oh->name);
4305 // directory stuff...
4306 // hook up to parent
4308 parent = yaffs_FindOrCreateObjectByNumber(dev,oh->parentObjectId,YAFFS_OBJECT_TYPE_DIRECTORY);
4309 if(parent->variantType == YAFFS_OBJECT_TYPE_UNKNOWN)
4311 // Set up as a directory
4312 parent->variantType = YAFFS_OBJECT_TYPE_DIRECTORY;
4313 INIT_LIST_HEAD(&parent->variant.directoryVariant.children);
4315 else if(parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
4317 // Hoosterman, another problem....
4318 // We're trying to use a non-directory as a directory
4320 T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." TENDSTR)));
4321 parent = dev->lostNFoundDir;
4324 yaffs_AddObjectToDirectory(parent,in);
4326 if(0 && (parent == dev->deletedDir ||
4327 parent == dev->unlinkedDir))
4329 in->deleted = 1; // If it is unlinked at start up then it wants deleting
4330 dev->nDeletedFiles++;
4333 // Note re hardlinks.
4334 // Since we might scan a hardlink before its equivalent object is scanned
4335 // we put them all in a list.
4336 // After scanning is complete, we should have all the objects, so we run through this
4337 // list and fix up all the chains.
4339 switch(in->variantType)
4341 case YAFFS_OBJECT_TYPE_UNKNOWN: // Todo got a problem
4343 case YAFFS_OBJECT_TYPE_FILE:
4344 if(dev->isYaffs2 && oh->isShrink)
4346 // Prune back the shrunken chunks
4347 yaffs_PruneResizedChunks(in,oh->fileSize);
4348 // Mark the block as having a shrinkHeader
4349 bi->hasShrinkHeader = 1;
4352 if(dev->useHeaderFileSize)
4354 in->variant.fileVariant.fileSize = oh->fileSize;
4357 case YAFFS_OBJECT_TYPE_HARDLINK:
4358 in->variant.hardLinkVariant.equivalentObjectId = oh->equivalentObjectId;
4359 in->hardLinks.next = (struct list_head *)hardList;
4362 case YAFFS_OBJECT_TYPE_DIRECTORY: // Do nothing
4364 case YAFFS_OBJECT_TYPE_SPECIAL: // Do nothing
4366 case YAFFS_OBJECT_TYPE_SYMLINK: // Do nothing
4367 in->variant.symLinkVariant.alias = yaffs_CloneString(oh->alias);
4371 if(parent == dev->deletedDir)
4373 yaffs_DestroyObject(in);
4374 bi->hasShrinkHeader = 1;
4376 //T((" %d %d header %d \"%s\" type %d\n",blk,c,tags.objectId,oh->name,in->variantType));
4381 if(state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
4383 // If we got this far while scanning, then the block is fully allocated.
4384 state = YAFFS_BLOCK_STATE_FULL;
4387 bi->blockState = state;
4389 // Now let's see if it was dirty
4390 if( bi->pagesInUse == 0 &&
4391 !bi->hasShrinkHeader &&
4392 bi->blockState == YAFFS_BLOCK_STATE_FULL)
4394 yaffs_BlockBecameDirty(dev,blk);
4404 // Ok, we've done all the scanning.
4406 // Fix up the hard link chains.
4407 // We should now have scanned all the objects, now it's time to add these
4412 hardList = (yaffs_Object *)(hardList->hardLinks.next);
4414 in = yaffs_FindObjectByNumber(dev,hl->variant.hardLinkVariant.equivalentObjectId);
4418 // Add the hardlink pointers
4419 hl->variant.hardLinkVariant.equivalentObject=in;
4420 list_add(&hl->hardLinks,&in->hardLinks);
4424 //Todo Need to report/handle this better.
4425 // Got a problem... hardlink to a non-existant object
4426 hl->variant.hardLinkVariant.equivalentObject=NULL;
4427 INIT_LIST_HEAD(&hl->hardLinks);
4433 // Handle the unlinked files. Since they were left in an unlinked state we should
4434 // just delete them.
4436 struct list_head *i;
4437 struct list_head *n;
4440 // Soft delete all the unlinked files
4441 list_for_each_safe(i,n,&dev->unlinkedDir->variant.directoryVariant.children)
4445 l = list_entry(i, yaffs_Object,siblings);
4446 yaffs_DestroyObject(l);
4451 yaffs_ReleaseTempBuffer(dev,chunkData,__LINE__);
4453 T(YAFFS_TRACE_SCAN,(TSTR("yaffs_Scan ends" TENDSTR)));
4459 static int yaffs_ScanBackwards(yaffs_Device *dev)
4461 yaffs_ExtendedTags tags;
4466 int nBlocksToScan = 0;
4471 yaffs_BlockState state;
4472 yaffs_Object *hardList = NULL;
4474 yaffs_BlockInfo *bi;
4476 yaffs_ObjectHeader *oh;
4478 yaffs_Object *parent;
4479 int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
4483 yaffs_BlockIndex *blockIndex = NULL;
4488 T(YAFFS_TRACE_SCAN,(TSTR("yaffs_ScanBackwards is only for YAFFS2!" TENDSTR)));
4492 T(YAFFS_TRACE_SCAN,(TSTR("yaffs_ScanBackwards starts intstartblk %d intendblk %d..." TENDSTR),dev->internalStartBlock,dev->internalEndBlock));
4494 chunkData = yaffs_GetTempBuffer(dev,__LINE__);
4497 dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
4499 blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
4502 // Scan all the blocks to determine their state
4503 for(blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++)
4505 bi = yaffs_GetBlockInfo(dev,blk);
4506 yaffs_ClearChunkBits(dev,blk);
4508 bi->softDeletions = 0;
4510 yaffs_QueryInitialBlockState(dev,blk,&state,&sequenceNumber);
4512 bi->blockState = state;
4513 bi->sequenceNumber = sequenceNumber;
4515 T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("Block scanning block %d state %d seq %d" TENDSTR),blk,state,sequenceNumber));
4517 if(state == YAFFS_BLOCK_STATE_DEAD)
4519 T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("block %d is bad" TENDSTR),blk));
4521 else if(state == YAFFS_BLOCK_STATE_EMPTY)
4523 T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("Block empty " TENDSTR)));
4524 dev->nErasedBlocks++;
4525 dev->nFreeChunks += dev->nChunksPerBlock;
4527 else if(state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
4530 // Determine the highest sequence number
4531 if( dev->isYaffs2 &&
4532 sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
4533 sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER)
4536 blockIndex[nBlocksToScan].seq = sequenceNumber;
4537 blockIndex[nBlocksToScan].block = blk;
4541 if(sequenceNumber >= dev->sequenceNumber)
4543 dev->sequenceNumber = sequenceNumber;
4546 else if(dev->isYaffs2)
4548 // TODO: Nasty sequence number!
4549 T(YAFFS_TRACE_SCAN,(TSTR("Block scanning block %d has bad sequence number %d" TENDSTR),blk,sequenceNumber));
4556 // Dungy old bubble sort for now...
4558 yaffs_BlockIndex temp;
4562 for(i = 0; i < nBlocksToScan; i++)
4563 for(j = i+1; j < nBlocksToScan; j++)
4564 if(blockIndex[i].seq > blockIndex[j].seq)
4566 temp = blockIndex[j];
4567 blockIndex[j] = blockIndex[i];
4568 blockIndex[i] = temp;
4573 // Now scan the blocks looking at the data.
4575 endIterator = nBlocksToScan-1;
4576 T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("%d blocks to be scanned" TENDSTR),nBlocksToScan));
4579 // For each block.... backwards
4580 for(blockIterator = endIterator; blockIterator >= startIterator; blockIterator--)
4583 // get the block to scan in the correct order
4584 blk = blockIndex[blockIterator].block;
4587 bi = yaffs_GetBlockInfo(dev,blk);
4588 state = bi->blockState;
4592 if( 0 && // Disable since this is redundant.
4593 state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
4595 // Let's look at the first chunk in the block
4596 chunk = blk * dev->nChunksPerBlock;
4598 yaffs_ReadChunkWithTagsFromNAND(dev,chunk,NULL,&tags);
4600 // Let's have a good look at this chunk...
4604 // An unassigned chunk in the block
4605 // This means that either the block is empty or
4606 // this is the one being allocated from
4608 // We're looking at the first chunk in the block so the block is unused
4609 state = YAFFS_BLOCK_STATE_EMPTY;
4610 dev->nErasedBlocks++;
4611 dev->nFreeChunks += dev->nChunksPerBlock;
4616 // For each chunk in each block that needs scanning....
4617 for(c = dev->nChunksPerBlock-1; c >= 0 &&
4618 (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
4619 state == YAFFS_BLOCK_STATE_ALLOCATING); c--)
4621 // Scan backwards...
4622 // Read the tags and decide what to do
4623 chunk = blk * dev->nChunksPerBlock + c;
4625 yaffs_ReadChunkWithTagsFromNAND(dev,chunk,NULL,&tags);
4627 // Let's have a good look at this chunk...
4631 // An unassigned chunk in the block
4632 // This means that either the block is empty or
4633 // this is the one being allocated from
4637 // We're looking at the first chunk in the block so the block is unused
4638 state = YAFFS_BLOCK_STATE_EMPTY;
4639 dev->nErasedBlocks++;
4643 // this is the block being allocated from
4644 if(state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
4646 T(YAFFS_TRACE_SCAN,(TSTR(" Allocating from %d %d" TENDSTR),blk,c));
4648 state = YAFFS_BLOCK_STATE_ALLOCATING;
4649 dev->allocationBlock = blk;
4650 dev->allocationPage = c;
4651 dev->allocationBlockFinder = blk; // Set it to here to encourage the allocator to
4652 // go forth from here.
4653 //Yaffs2 sanity check:
4654 // This should be the one with the highest sequence number
4655 if(dev->isYaffs2 && (dev->sequenceNumber != bi->sequenceNumber))
4657 T(YAFFS_TRACE_ALWAYS,
4658 (TSTR("yaffs: Allocation block %d was not highest sequence id: block seq = %d, dev seq = %d" TENDSTR),
4659 blk,bi->sequenceNumber,dev->sequenceNumber));
4663 dev->nFreeChunks ++;
4665 else if(tags.chunkId > 0)
4667 // chunkId > 0 so it is a data chunk...
4668 unsigned int endpos;
4670 __u32 chunkBase = (tags.chunkId - 1)* dev->nBytesPerChunk;
4672 yaffs_SetChunkBit(dev,blk,c);
4675 in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,YAFFS_OBJECT_TYPE_FILE);
4676 if(in->variantType == YAFFS_OBJECT_TYPE_FILE &&
4677 chunkBase < in->variant.fileVariant.shrinkSize)
4679 // This has not been invalidated by a resize
4680 yaffs_PutChunkIntoFile(in,tags.chunkId,chunk,-1);
4683 // File size is calculated by looking at the data chunks if we have not
4684 // seen an object header yet. Stop this practice once we find an object header.
4685 endpos = (tags.chunkId - 1)* dev->nBytesPerChunk + tags.byteCount;
4686 if(!in->valid && // have not got an object header yet
4687 in->variant.fileVariant.scannedFileSize <endpos)
4689 in->variant.fileVariant.scannedFileSize = endpos;
4690 in->variant.fileVariant.fileSize = in->variant.fileVariant.scannedFileSize;
4696 // This chunk has been invalidated by a resize, so delete
4697 yaffs_DeleteChunk(dev,chunk,1,__LINE__);
4701 //T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId));
4705 // chunkId == 0, so it is an ObjectHeader.
4706 // Thus, we read in the object header and make the object
4707 yaffs_SetChunkBit(dev,blk,c);
4713 if(tags.extraHeaderInfoAvailable)
4715 in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,tags.extraObjectType);
4719 if(!in || !in->valid)
4722 // If we don't have valid info then we need to read the chunk
4723 // TODO In future we can probably defer reading the chunk and
4724 // living with invalid data until needed.
4726 yaffs_ReadChunkWithTagsFromNAND(dev,chunk,chunkData,NULL);
4728 oh = (yaffs_ObjectHeader *)chunkData;
4731 in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,oh->type);
4737 // TODO Hoosterman we have a problem!
4738 T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: Could not make object for object %d at chunk %d during scan" TENDSTR),tags.objectId,chunk));
4744 // We have already filled this one. We have a duplicate that will be discarded, but
4745 // we first have to suck out resize info if it is a file.
4747 if( (in->variantType == YAFFS_OBJECT_TYPE_FILE) &&
4748 ((oh && oh->type == YAFFS_OBJECT_TYPE_FILE) ||
4749 (tags.extraHeaderInfoAvailable && tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE))
4752 __u32 thisSize = (oh) ? oh->fileSize : tags.extraFileLength;
4753 __u32 parentObjectId = (oh) ? oh->parentObjectId : tags.extraParentObjectId;
4754 unsigned isShrink = (oh) ? oh->isShrink : tags.extraIsShrinkHeader;
4756 // If it is deleted (unlinked at start also means deleted)
4757 // we treat the file size as being zeroed at this point.
4758 if(parentObjectId == YAFFS_OBJECTID_DELETED ||
4759 parentObjectId == YAFFS_OBJECTID_UNLINKED)
4766 in->variant.fileVariant.shrinkSize > thisSize)
4768 in->variant.fileVariant.shrinkSize = thisSize;
4773 bi->hasShrinkHeader = 1;
4777 // Use existing - destroy this one.
4778 yaffs_DeleteChunk(dev,chunk,1,__LINE__);
4783 (tags.objectId == YAFFS_OBJECTID_ROOT ||
4784 tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))
4786 // We only load some info, don't fiddle with directory structure
4788 in->variantType = oh->type;
4790 in->yst_mode = oh->yst_mode;
4791 #ifdef CONFIG_YAFFS_WINCE
4792 in->win_atime[0] = oh->win_atime[0];
4793 in->win_ctime[0] = oh->win_ctime[0];
4794 in->win_mtime[0] = oh->win_mtime[0];
4795 in->win_atime[1] = oh->win_atime[1];
4796 in->win_ctime[1] = oh->win_ctime[1];
4797 in->win_mtime[1] = oh->win_mtime[1];
4799 in->yst_uid = oh->yst_uid;
4800 in->yst_gid = oh->yst_gid;
4801 in->yst_atime = oh->yst_atime;
4802 in->yst_mtime = oh->yst_mtime;
4803 in->yst_ctime = oh->yst_ctime;
4804 in->yst_rdev = oh->yst_rdev;
4806 in->chunkId = chunk;
4811 // we need to load this info
4814 in->variantType = oh->type;
4816 in->yst_mode = oh->yst_mode;
4817 #ifdef CONFIG_YAFFS_WINCE
4818 in->win_atime[0] = oh->win_atime[0];
4819 in->win_ctime[0] = oh->win_ctime[0];
4820 in->win_mtime[0] = oh->win_mtime[0];
4821 in->win_atime[1] = oh->win_atime[1];
4822 in->win_ctime[1] = oh->win_ctime[1];
4823 in->win_mtime[1] = oh->win_mtime[1];
4825 in->yst_uid = oh->yst_uid;
4826 in->yst_gid = oh->yst_gid;
4827 in->yst_atime = oh->yst_atime;
4828 in->yst_mtime = oh->yst_mtime;
4829 in->yst_ctime = oh->yst_ctime;
4830 in->yst_rdev = oh->yst_rdev;
4832 in->chunkId = chunk;
4834 if(oh->shadowsObject > 0)
4836 yaffs_HandleShadowedObject(dev,oh->shadowsObject,1);
4840 yaffs_SetObjectName(in,oh->name);
4843 // directory stuff...
4844 // hook up to parent
4846 parent = yaffs_FindOrCreateObjectByNumber(dev,oh->parentObjectId,YAFFS_OBJECT_TYPE_DIRECTORY);
4847 if(parent->variantType == YAFFS_OBJECT_TYPE_UNKNOWN)
4849 // Set up as a directory
4850 parent->variantType = YAFFS_OBJECT_TYPE_DIRECTORY;
4851 INIT_LIST_HEAD(&parent->variant.directoryVariant.children);
4853 else if(parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
4855 // Hoosterman, another problem....
4856 // We're trying to use a non-directory as a directory
4858 T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." TENDSTR)));
4859 parent = dev->lostNFoundDir;
4862 yaffs_AddObjectToDirectory(parent,in);
4864 if((parent == dev->deletedDir ||
4865 parent == dev->unlinkedDir))
4867 in->deleted = 1; // If it is unlinked at start up then it wants deleting
4872 // Mark the block as having a shrinkHeader
4873 bi->hasShrinkHeader = 1;
4877 // Note re hardlinks.
4878 // Since we might scan a hardlink before its equivalent object is scanned
4879 // we put them all in a list.
4880 // After scanning is complete, we should have all the objects, so we run through this
4881 // list and fix up all the chains.
4883 switch(in->variantType)
4885 case YAFFS_OBJECT_TYPE_UNKNOWN: // Todo got a problem
4887 case YAFFS_OBJECT_TYPE_FILE:
4890 if(in->variant.fileVariant.scannedFileSize < oh->fileSize)
4892 // This covers the case where the file size is > than where the data is
4893 // This will happen if the file is resized to be larger than its current
4895 in->variant.fileVariant.fileSize = oh->fileSize;
4896 in->variant.fileVariant.scannedFileSize = in->variant.fileVariant.fileSize;
4900 in->variant.fileVariant.shrinkSize > oh->fileSize)
4902 in->variant.fileVariant.shrinkSize = oh->fileSize;
4906 case YAFFS_OBJECT_TYPE_HARDLINK:
4907 in->variant.hardLinkVariant.equivalentObjectId = oh->equivalentObjectId;
4908 in->hardLinks.next = (struct list_head *)hardList;
4911 case YAFFS_OBJECT_TYPE_DIRECTORY: // Do nothing
4913 case YAFFS_OBJECT_TYPE_SPECIAL: // Do nothing
4915 case YAFFS_OBJECT_TYPE_SYMLINK: // Do nothing
4916 in->variant.symLinkVariant.alias = yaffs_CloneString(oh->alias);
4920 //T((" %d %d header %d \"%s\" type %d\n",blk,c,tags.objectId,oh->name,in->variantType));
4925 if(state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
4927 // If we got this far while scanning, then the block is fully allocated.
4928 state = YAFFS_BLOCK_STATE_FULL;
4931 bi->blockState = state;
4933 // Now let's see if it was dirty
4934 if( bi->pagesInUse == 0 &&
4935 !bi->hasShrinkHeader &&
4936 bi->blockState == YAFFS_BLOCK_STATE_FULL)
4938 yaffs_BlockBecameDirty(dev,blk);
4948 // Ok, we've done all the scanning.
4950 // Fix up the hard link chains.
4951 // We should now have scanned all the objects, now it's time to add these
4956 hardList = (yaffs_Object *)(hardList->hardLinks.next);
4958 in = yaffs_FindObjectByNumber(dev,hl->variant.hardLinkVariant.equivalentObjectId);
4962 // Add the hardlink pointers
4963 hl->variant.hardLinkVariant.equivalentObject=in;
4964 list_add(&hl->hardLinks,&in->hardLinks);
4968 //Todo Need to report/handle this better.
4969 // Got a problem... hardlink to a non-existant object
4970 hl->variant.hardLinkVariant.equivalentObject=NULL;
4971 INIT_LIST_HEAD(&hl->hardLinks);
4978 struct list_head *i;
4979 struct list_head *n;
4983 // Soft delete all the unlinked files
4984 list_for_each_safe(i,n,&dev->unlinkedDir->variant.directoryVariant.children)
4988 l = list_entry(i, yaffs_Object,siblings);
4989 yaffs_DestroyObject(l);
4993 // Soft delete all the deletedDir files
4994 list_for_each_safe(i,n,&dev->deletedDir->variant.directoryVariant.children)
4998 l = list_entry(i, yaffs_Object,siblings);
4999 yaffs_DestroyObject(l);
5005 yaffs_ReleaseTempBuffer(dev,chunkData,__LINE__);
5007 T(YAFFS_TRACE_SCAN,(TSTR("yaffs_ScanBackwards ends" TENDSTR)));
5014 ////////////////////////// Directory Functions /////////////////////////
5017 static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj)
5022 T(YAFFS_TRACE_ALWAYS,(TSTR("tragedy: Trying to add an object to a null pointer directory" TENDSTR)));
5025 if(directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
5027 T(YAFFS_TRACE_ALWAYS,(TSTR("tragedy: Trying to add an object to a non-directory" TENDSTR)));
5031 if(obj->siblings.prev == NULL)
5034 INIT_LIST_HEAD(&obj->siblings);
5037 else if(!list_empty(&obj->siblings))
5039 // If it is holed up somewhere else, un hook it
5040 list_del_init(&obj->siblings);
5043 list_add(&obj->siblings,&directory->variant.directoryVariant.children);
5044 obj->parent = directory;
5046 if(directory == obj->myDev->unlinkedDir || directory == obj->myDev->deletedDir)
5049 obj->myDev->nUnlinkedFiles++;
5050 obj->renameAllowed = 0;
5054 static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj)
5056 list_del_init(&obj->siblings);
5060 yaffs_Object *yaffs_FindObjectByName(yaffs_Object *directory,const YCHAR *name)
5064 struct list_head *i;
5065 YCHAR buffer[YAFFS_MAX_NAME_LENGTH+1];
5076 T(YAFFS_TRACE_ALWAYS,(TSTR("tragedy: yaffs_FindObjectByName: null pointer directory"TENDSTR)));
5079 if(directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
5081 T(YAFFS_TRACE_ALWAYS,(TSTR("tragedy: yaffs_FindObjectByName: non-directory"TENDSTR)));
5085 sum = yaffs_CalcNameSum(name);
5087 list_for_each(i,&directory->variant.directoryVariant.children)
5091 l = list_entry(i, yaffs_Object,siblings);
5093 // Special case for lost-n-found
5094 if(l->objectId == YAFFS_OBJECTID_LOSTNFOUND)
5096 if(yaffs_strcmp(name,YAFFS_LOSTNFOUND_NAME) == 0)
5101 else if(yaffs_SumCompare(l->sum, sum)||
5102 l->chunkId <= 0) //LostnFound cunk called Objxxx
5105 yaffs_GetObjectName(l,buffer,YAFFS_MAX_NAME_LENGTH);
5106 if(yaffs_strcmp(name,buffer) == 0)
5119 int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir,int (*fn)(yaffs_Object *))
5121 struct list_head *i;
5127 T(YAFFS_TRACE_ALWAYS,(TSTR("tragedy: yaffs_FindObjectByName: null pointer directory"TENDSTR)));
5130 if(theDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
5132 T(YAFFS_TRACE_ALWAYS,(TSTR("tragedy: yaffs_FindObjectByName: non-directory"TENDSTR)));
5136 list_for_each(i,&theDir->variant.directoryVariant.children)
5140 l = list_entry(i, yaffs_Object,siblings);
5153 // GetEquivalentObject dereferences any hard links to get to the
5156 yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj)
5158 if(obj && obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
5160 // We want the object id of the equivalent object, not this one
5161 obj = obj->variant.hardLinkVariant.equivalentObject;
5167 int yaffs_GetObjectName(yaffs_Object *obj,YCHAR *name,int buffSize)
5169 memset(name,0,buffSize * sizeof(YCHAR));
5171 if(obj->objectId == YAFFS_OBJECTID_LOSTNFOUND)
5173 yaffs_strncpy(name,YAFFS_LOSTNFOUND_NAME,buffSize - 1);
5175 else if(obj->chunkId <= 0)
5179 yaffs_sprintf(locName,_Y("%s%d"),YAFFS_LOSTNFOUND_PREFIX,obj->objectId);
5180 yaffs_strncpy(name,locName,buffSize - 1);
5183 #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
5184 else if(obj->shortName[0])
5186 yaffs_strcpy(name,obj->shortName);
5191 __u8 *buffer = yaffs_GetTempBuffer(obj->myDev,__LINE__);
5193 yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)buffer;
5195 memset(buffer,0,obj->myDev->nBytesPerChunk);
5197 if(obj->chunkId >= 0)
5199 yaffs_ReadChunkWithTagsFromNAND(obj->myDev,obj->chunkId,buffer,NULL);
5201 yaffs_strncpy(name,oh->name,buffSize - 1);
5203 yaffs_ReleaseTempBuffer(obj->myDev,buffer,__LINE__);
5206 return yaffs_strlen(name);
5209 int yaffs_GetObjectFileLength(yaffs_Object *obj)
5212 // Dereference any hard linking
5213 obj = yaffs_GetEquivalentObject(obj);
5215 if(obj->variantType == YAFFS_OBJECT_TYPE_FILE)
5217 return obj->variant.fileVariant.fileSize;
5219 if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
5221 return yaffs_strlen(obj->variant.symLinkVariant.alias);
5225 // Only a directory should drop through to here
5226 return obj->myDev->nBytesPerChunk;
5230 int yaffs_GetObjectLinkCount(yaffs_Object *obj)
5233 struct list_head *i;
5237 count++; // the object itself
5239 list_for_each(i,&obj->hardLinks)
5241 count++; // add the hard links;
5248 int yaffs_GetObjectInode(yaffs_Object *obj)
5250 obj = yaffs_GetEquivalentObject(obj);
5252 return obj->objectId;
5255 unsigned yaffs_GetObjectType(yaffs_Object *obj)
5257 obj = yaffs_GetEquivalentObject(obj);
5259 switch(obj->variantType)
5261 case YAFFS_OBJECT_TYPE_FILE: return DT_REG; break;
5262 case YAFFS_OBJECT_TYPE_DIRECTORY: return DT_DIR; break;
5263 case YAFFS_OBJECT_TYPE_SYMLINK: return DT_LNK; break;
5264 case YAFFS_OBJECT_TYPE_HARDLINK: return DT_REG; break;
5265 case YAFFS_OBJECT_TYPE_SPECIAL:
5266 if(S_ISFIFO(obj->yst_mode)) return DT_FIFO;
5267 if(S_ISCHR(obj->yst_mode)) return DT_CHR;
5268 if(S_ISBLK(obj->yst_mode)) return DT_BLK;
5269 if(S_ISSOCK(obj->yst_mode)) return DT_SOCK;
5270 default: return DT_REG; break;
5274 YCHAR *yaffs_GetSymlinkAlias(yaffs_Object *obj)
5276 obj = yaffs_GetEquivalentObject(obj);
5277 if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
5279 return yaffs_CloneString(obj->variant.symLinkVariant.alias);
5283 return yaffs_CloneString(_Y(""));
5287 #ifndef CONFIG_YAFFS_WINCE
5289 int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr)
5291 unsigned int valid = attr->ia_valid;
5293 if(valid & ATTR_MODE) obj->yst_mode = attr->ia_mode;
5294 if(valid & ATTR_UID) obj->yst_uid = attr->ia_uid;
5295 if(valid & ATTR_GID) obj->yst_gid = attr->ia_gid;
5297 if(valid & ATTR_ATIME) obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
5298 if(valid & ATTR_CTIME) obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime);
5299 if(valid & ATTR_MTIME) obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
5301 if(valid & ATTR_SIZE) yaffs_ResizeFile(obj,attr->ia_size);
5303 yaffs_UpdateObjectHeader(obj,NULL,1,0,0);
5308 int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr)
5310 unsigned int valid = 0;
5312 attr->ia_mode = obj->yst_mode; valid |= ATTR_MODE;
5313 attr->ia_uid = obj->yst_uid; valid |= ATTR_UID;
5314 attr->ia_gid = obj->yst_gid; valid |= ATTR_GID;
5316 Y_TIME_CONVERT(attr->ia_atime)= obj->yst_atime; valid |= ATTR_ATIME;
5317 Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime; valid |= ATTR_CTIME;
5318 Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime; valid |= ATTR_MTIME;
5320 attr->ia_size = yaffs_GetFileSize(obj); valid |= ATTR_SIZE;
5322 attr->ia_valid = valid;
5330 int yaffs_DumpObject(yaffs_Object *obj)
5332 // __u8 buffer[YAFFS_BYTES_PER_CHUNK];
5334 // yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)buffer;
5336 // memset(buffer,0,YAFFS_BYTES_PER_CHUNK);
5338 // if(obj->chunkId >= 0)
5340 // yaffs_ReadChunkFromNAND(obj->myDev,obj->chunkId,buffer,NULL);
5343 yaffs_GetObjectName(obj,name,256);
5345 T(YAFFS_TRACE_ALWAYS,(TSTR("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d chunk %d type %d size %d\n" TENDSTR),
5346 obj->objectId,yaffs_GetObjectInode(obj), name, obj->dirty, obj->valid, obj->serial,
5347 obj->sum, obj->chunkId, yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj)));
5355 ///////////////////////// Initialisation code ///////////////////////////
5358 static int yaffs_CheckDevFunctions(const yaffs_Device *dev)
5361 // Common functions, gotta have
5362 if(!dev->eraseBlockInNAND ||
5363 !dev->initialiseNAND) return 0;
5365 #ifdef CONFIG_YAFFS_YAFFS2
5367 // Can use the "with tags" style interface for yaffs1 or yaffs2
5368 if(dev->writeChunkWithTagsToNAND &&
5369 dev->readChunkWithTagsFromNAND &&
5370 !dev->writeChunkToNAND &&
5371 !dev->readChunkFromNAND &&
5372 dev->markNANDBlockBad &&
5373 dev->queryNANDBlock) return 1;
5376 // Can use the "spare" style interface for yaffs1
5377 if(!dev->isYaffs2 &&
5378 !dev->writeChunkWithTagsToNAND &&
5379 !dev->readChunkWithTagsFromNAND &&
5380 dev->writeChunkToNAND &&
5381 dev->readChunkFromNAND &&
5382 !dev->markNANDBlockBad &&
5383 !dev->queryNANDBlock) return 1;
5389 int yaffs_GutsInitialise(yaffs_Device *dev)
5396 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: yaffs_GutsInitialise()" TENDSTR)));
5397 // Check stuff that must be set
5401 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Need a device" TENDSTR)));
5405 dev->internalStartBlock = dev->startBlock;
5406 dev->internalEndBlock = dev->endBlock;
5407 dev->blockOffset = 0;
5408 dev->chunkOffset = 0;
5409 dev->nFreeChunks = 0;
5411 if(dev->startBlock == 0)
5413 dev->internalStartBlock = dev->startBlock + 1;
5414 dev->internalEndBlock = dev->endBlock + 1;
5415 dev->blockOffset = 1;
5416 dev->chunkOffset = dev->nChunksPerBlock;
5419 // Check geometry parameters.
5421 if( (dev->isYaffs2 && dev->nBytesPerChunk <1024) ||
5422 (!dev->isYaffs2 && dev->nBytesPerChunk !=512) ||
5423 dev->nChunksPerBlock < 2 ||
5424 dev->nReservedBlocks < 2 ||
5425 dev->internalStartBlock <= 0 ||
5426 dev->internalEndBlock <= 0 ||
5427 dev->internalEndBlock <= (dev->internalStartBlock + dev->nReservedBlocks + 2) // otherwise it is too small
5430 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s " TENDSTR),
5431 dev->nBytesPerChunk, dev->isYaffs2 ? "2" : ""));
5435 if(yaffs_InitialiseNAND(dev) != YAFFS_OK)
5437 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: InitialiseNAND failed" TENDSTR)));
5441 // Got the right mix of functions?
5443 if(!yaffs_CheckDevFunctions(dev))
5446 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: device function(s) missing or wrong\n" TENDSTR)));
5451 // This is really a compilation check.
5452 if(!yaffs_CheckStructures())
5454 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs_CheckStructures failed\n" TENDSTR)));
5460 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: device already mounted\n" TENDSTR)));
5466 // Finished with most checks. One or two more checks happen later on too.
5472 nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
5476 // OK now calculate a few things for the device
5477 // Calculate chunkGroupBits.
5478 // We need to find the next power of 2 > than internalEndBlock
5480 x = dev->nChunksPerBlock * (dev->internalEndBlock+1);
5482 for(bits = extraBits = 0; x > 1; bits++)
5484 if(x & 1) extraBits++;
5488 if(extraBits > 0) bits++;
5491 // Level0 Tnodes are 16 bits, so if the bitwidth of the
5492 // chunk range we're using is greater than 16 we need
5493 // to figure out chunk shift and chunkGroupSize
5496 dev->chunkGroupBits = 0;
5500 dev->chunkGroupBits = bits - 16;
5503 dev->chunkGroupSize = 1 << dev->chunkGroupBits;
5505 if(dev->nChunksPerBlock < dev->chunkGroupSize)
5507 // We have a problem because the soft delete won't work if
5508 // the chunk group size > chunks per block.
5509 // This can be remedied by using larger "virtual blocks".
5510 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: chunk group too large\n" TENDSTR)));
5516 // OK, we've finished verifying the device, lets continue with initialisation
5518 // More device initialisation
5519 dev->garbageCollections = 0;
5520 dev->passiveGarbageCollections = 0;
5521 dev->currentDirtyChecker = 0;
5522 dev->bufferedBlock = -1;
5523 dev->doingBufferedBlockRewrite = 0;
5524 dev->nDeletedFiles = 0;
5525 dev->nBackgroundDeletions=0;
5526 dev->nUnlinkedFiles = 0;
5529 dev->tagsEccFixed=0;
5530 dev->tagsEccUnfixed=0;
5531 dev->nErasureFailures = 0;
5532 dev->nErasedBlocks = 0;
5535 //dev->localBuffer = YMALLOC(dev->nBytesPerChunk);
5536 // Initialise temporary buffers
5539 for(i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
5541 dev->tempBuffer[i].line = 0; // not in use
5542 dev->tempBuffer[i].buffer = YMALLOC(dev->nBytesPerChunk);
5548 yaffs_InitialiseBlocks(dev,nBlocks);
5550 yaffs_InitialiseTnodes(dev);
5552 yaffs_InitialiseObjects(dev);
5554 dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32));
5556 if(dev->nShortOpCaches > 0)
5560 if(dev->nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES)
5562 dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES;
5565 dev->srCache = YMALLOC( dev->nShortOpCaches * sizeof(yaffs_ChunkCache));
5567 for(i=0; i < dev->nShortOpCaches; i++)
5569 dev->srCache[i].object = NULL;
5570 dev->srCache[i].lastUse = 0;
5571 dev->srCache[i].dirty = 0;
5572 dev->srCache[i].data = YMALLOC(dev->nBytesPerChunk);
5580 // Initialise the unlinked, root and lost and found directories
5581 dev->lostNFoundDir = dev->rootDir = dev->unlinkedDir = dev->deletedDir = NULL;
5583 dev->unlinkedDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_UNLINKED, S_IFDIR);
5584 dev->deletedDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_DELETED, S_IFDIR);
5586 dev->rootDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_ROOT,YAFFS_ROOT_MODE | S_IFDIR);
5587 dev->lostNFoundDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_LOSTNFOUND,YAFFS_LOSTNFOUND_MODE | S_IFDIR);
5588 yaffs_AddObjectToDirectory(dev->rootDir,dev->lostNFoundDir);
5592 dev->useHeaderFileSize = 1;
5595 // Now scan the flash.
5598 yaffs_ScanBackwards(dev);
5603 dev->nPageReads = 0;
5604 dev->nPageWrites = 0;
5605 dev->nBlockErasures = 0;
5607 dev->nRetriedWrites = 0;
5609 dev->nRetiredBlocks = 0;
5611 yaffs_VerifyFreeChunks(dev);
5613 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));
5618 void yaffs_Deinitialise(yaffs_Device *dev)
5624 yaffs_DeinitialiseBlocks(dev);
5625 yaffs_DeinitialiseTnodes(dev);
5626 yaffs_DeinitialiseObjects(dev);
5627 if(dev->nShortOpCaches > 0)
5630 for(i=0; i < dev->nShortOpCaches; i++)
5632 YFREE(dev->srCache[i].data);
5635 YFREE(dev->srCache);
5638 YFREE(dev->gcCleanupList);
5640 for(i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
5642 YFREE(dev->tempBuffer[i].buffer);
5651 static int yaffs_CountFreeChunks(yaffs_Device *dev)
5656 yaffs_BlockInfo *blk;
5659 for(nFree = 0, b = dev->internalStartBlock; b <= dev->internalEndBlock; b++)
5661 blk = yaffs_GetBlockInfo(dev,b);
5663 switch(blk->blockState)
5665 case YAFFS_BLOCK_STATE_EMPTY:
5666 case YAFFS_BLOCK_STATE_ALLOCATING:
5667 case YAFFS_BLOCK_STATE_COLLECTING:
5668 case YAFFS_BLOCK_STATE_FULL: nFree += (dev->nChunksPerBlock - blk->pagesInUse + blk->softDeletions); break;
5679 int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
5681 // This is what we report to the outside world
5684 int nDirtyCacheChunks;
5687 nFree = dev->nFreeChunks;
5689 nFree = yaffs_CountFreeChunks(dev);
5692 // Now count the number of dirty chunks in the cache and subtract those
5696 for( nDirtyCacheChunks = 0,i = 0; i < dev->nShortOpCaches; i++)
5698 if(dev->srCache[i].dirty) nDirtyCacheChunks++;
5702 nFree -= nDirtyCacheChunks;
5704 nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock);
5706 if(nFree < 0) nFree = 0;
5712 static int yaffs_freeVerificationFailures;
5714 static void yaffs_VerifyFreeChunks(yaffs_Device *dev)
5716 int counted = yaffs_CountFreeChunks(dev);
5718 int difference = dev->nFreeChunks - counted;
5722 T(YAFFS_TRACE_ALWAYS,(TSTR("Freechunks verification failure %d %d %d" TENDSTR),dev->nFreeChunks,counted,difference));
5723 yaffs_freeVerificationFailures++;
5727 /////////////////// YAFFS test code //////////////////////////////////
5729 #define yaffs_CheckStruct(structure,syze, name) \
5730 if(sizeof(structure) != syze) \
5732 T(YAFFS_TRACE_ALWAYS,(TSTR("%s should be %d but is %d\n" TENDSTR),name,syze,sizeof(structure))); \
5733 return YAFFS_FAIL; \
5737 static int yaffs_CheckStructures(void)
5739 // yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags")
5740 // yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion")
5741 // yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare")
5742 #ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG
5743 yaffs_CheckStruct(yaffs_Tnode,2* YAFFS_NTNODES_LEVEL0,"yaffs_Tnode")
5745 yaffs_CheckStruct(yaffs_ObjectHeader,512,"yaffs_ObjectHeader")