3 * YAFFS: Yet another FFS. A NAND-flash specific file system.
5 * Copyright (C) 2002 Aleph One Ltd.
6 * for Toby Churchill Ltd and Brightstar Engineering
8 * Created by Charles Manning <charles@aleph1.co.uk>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
17 const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.8 2005-07-05 23:54:59 charles Exp $";
21 #include "yaffsinterface.h"
22 #include "yaffs_guts.h"
23 #include "yaffs_tagsvalidity.h"
26 #include "yaffs_tagscompat.h"
28 #ifdef CONFIG_YAFFS_WINCE
29 void yfsd_LockYAFFS(BOOL fsLockOnly);
30 void yfsd_UnlockYAFFS(BOOL fsLockOnly);
33 #define YAFFS_PASSIVE_GC_CHUNKS 2
36 // Use Steven Hill's ECC struff instead
37 // External functions for ECC on data
38 void nand_calculate_ecc (const u_char *dat, u_char *ecc_code);
39 int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc);
40 #define yaffs_ECCCalculate(data,ecc) nand_calculate_ecc(data,ecc)
41 #define yaffs_ECCCorrect(data,read_ecc,calc_ecc) nand_correct_ecc(data,read_ecc,calc_ecc)
43 #include "yaffs_ecc.h"
47 // countBits is a quick way of counting the number of bits in a byte.
48 // ie. countBits[n] holds the number of 1 bits in a byte with the value n.
50 static const char yaffs_countBitsTable[256] =
52 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,
53 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
54 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
55 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
56 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
57 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
58 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
59 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
60 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
61 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
62 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
63 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
64 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
65 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
66 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
67 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8
70 static int yaffs_CountBits(__u8 x)
73 retVal = yaffs_countBitsTable[x];
81 // Stuff using yea olde tags
82 static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr);
83 static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr);
85 static int yaffs_ReadChunkTagsFromNAND(yaffs_Device *dev,int chunkInNAND, yaffs_Tags *tags, int *chunkDeleted);
86 static int yaffs_TagsMatch(const yaffs_Tags *tags, int objectId, int chunkInObject, int chunkDeleted);
93 static Y_INLINE int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *buffer, yaffs_ExtendedTags *tags);
94 static Y_INLINE int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND, const __u8 *data, yaffs_ExtendedTags *tags);
95 static Y_INLINE int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo);
96 static Y_INLINE int yaffs_QueryInitialBlockState(yaffs_Device *dev,int blockNo, yaffs_BlockState *state,unsigned *sequenceNumber);
98 static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, const __u8 *buffer, yaffs_ExtendedTags *tags, int useReserve);
100 static int yaffs_CheckObjectHashSanity(yaffs_Device *dev);
102 static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan);
104 static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type);
105 static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj);
106 static int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int isShrink);
107 static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj);
108 static int yaffs_CheckStructures(void);
109 static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset,int *limit);
110 static int yaffs_DoGenericObjectDeletion(yaffs_Object *in);
112 static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device *dev,int blockNo);
114 static __u8 *yaffs_GetTempBuffer(yaffs_Device *dev,int lineNo);
115 static void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, int lineNo);
118 // Robustification (if it ever comes about...)
119 static void yaffs_RetireBlock(yaffs_Device *dev,int blockInNAND);
121 static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND);
123 static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND);
124 static void yaffs_HandleWriteChunkOk(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *tags);
125 static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND, const yaffs_ExtendedTags *tags);
127 static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND);
129 static int yaffs_UnlinkWorker(yaffs_Object *obj);
130 static void yaffs_DestroyObject(yaffs_Object *obj);
133 static int yaffs_VerifyCompare(const __u8 *d0, const __u8 * d1, const yaffs_Spare *s0, const yaffs_Spare *s1,int dataSize);
136 static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId, int chunkInObject);
139 loff_t yaffs_GetFileSize(yaffs_Object *obj);
142 static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve);
144 #ifdef YAFFS_PARANOID
145 static int yaffs_CheckFileSanity(yaffs_Object *in);
147 #define yaffs_CheckFileSanity(in)
150 static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in);
151 static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId);
153 static int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *buffer, yaffs_ExtendedTags *tags)
155 chunkInNAND -= dev->chunkOffset;
157 if(dev->readChunkWithTagsFromNAND)
158 return dev->readChunkWithTagsFromNAND(dev,chunkInNAND,buffer,tags);
160 return yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev,chunkInNAND,buffer,tags);
163 static Y_INLINE int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND, const __u8 *buffer, yaffs_ExtendedTags *tags)
165 chunkInNAND -= dev->chunkOffset;
169 tags->sequenceNumber = dev->sequenceNumber;
171 if(!yaffs_ValidateTags(tags))
173 T(YAFFS_TRACE_ERROR,(TSTR("Writing uninitialised tags" TENDSTR)));
176 T(YAFFS_TRACE_WRITE,(TSTR("Writing chunk %d tags %d %d"TENDSTR),chunkInNAND,tags->objectId,tags->chunkId));
180 T(YAFFS_TRACE_ERROR,(TSTR("Writing with no tags" TENDSTR)));
184 if(dev->writeChunkWithTagsToNAND)
185 return dev->writeChunkWithTagsToNAND(dev,chunkInNAND,buffer,tags);
187 return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev,chunkInNAND,buffer,tags);
190 static Y_INLINE int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo)
192 blockNo -= dev->blockOffset;
194 if(dev->markNANDBlockBad)
195 return dev->markNANDBlockBad(dev,blockNo);
197 return yaffs_TagsCompatabilityMarkNANDBlockBad(dev,blockNo);
199 static Y_INLINE int yaffs_QueryInitialBlockState(yaffs_Device *dev,int blockNo, yaffs_BlockState *state, unsigned *sequenceNumber)
201 blockNo -= dev->blockOffset;
203 if(dev->queryNANDBlock)
204 return dev->queryNANDBlock(dev,blockNo,state,sequenceNumber);
206 return yaffs_TagsCompatabilityQueryNANDBlock(dev,blockNo,state,sequenceNumber);
209 int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND)
213 blockInNAND -= dev->blockOffset;
215 dev->nBlockErasures++;
216 result = dev->eraseBlockInNAND(dev,blockInNAND);
218 if(!result)result = dev->eraseBlockInNAND(dev,blockInNAND); // If at first we don't succeed, try again *once*.
222 static int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
224 return dev->initialiseNAND(dev);
230 // Temporary buffer manipulations
232 static __u8 *yaffs_GetTempBuffer(yaffs_Device *dev,int lineNo)
235 for(i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
237 if(dev->tempBuffer[i].line == 0)
239 dev->tempBuffer[i].line = lineNo;
240 if((i+1) > dev->maxTemp)
242 dev->maxTemp = i + 1;
243 for(j = 0; j <= i; j++)
244 dev->tempBuffer[j].maxLine = dev->tempBuffer[j].line;
247 return dev->tempBuffer[i].buffer;
251 T(YAFFS_TRACE_BUFFERS,(TSTR("Out of temp buffers at line %d, other held by lines:"),lineNo));
252 for(i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
254 T(YAFFS_TRACE_BUFFERS,(TSTR(" %d "),dev->tempBuffer[i].line));
256 T(YAFFS_TRACE_BUFFERS,(TSTR(" "TENDSTR)));
258 dev->unmanagedTempAllocations++;
259 // Get an unmanaged one
260 return YMALLOC(dev->nBytesPerChunk);
265 static void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, int lineNo)
268 for(i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
270 if(dev->tempBuffer[i].buffer == buffer)
272 dev->tempBuffer[i].line = 0;
279 // assume it is an unmanaged one.
280 T(YAFFS_TRACE_BUFFERS,(TSTR("Releasing unmanaged temp buffer in line %d" TENDSTR),lineNo));
282 dev->unmanagedTempDeallocations++;
288 // Chunk bitmap manipulations
290 static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk)
292 if(blk < dev->internalStartBlock || blk > dev->internalEndBlock)
294 T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),blk));
297 return dev->chunkBits + (dev->chunkBitmapStride * (blk - dev->internalStartBlock));
300 static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device *dev,int blk)
302 __u8 *blkBits = yaffs_BlockBits(dev,blk);
304 memset(blkBits,0,dev->chunkBitmapStride);
307 static Y_INLINE void yaffs_ClearChunkBit(yaffs_Device *dev,int blk,int chunk)
309 __u8 *blkBits = yaffs_BlockBits(dev,blk);
311 blkBits[chunk/8] &= ~ (1<<(chunk & 7));
314 static Y_INLINE void yaffs_SetChunkBit(yaffs_Device *dev,int blk,int chunk)
316 __u8 *blkBits = yaffs_BlockBits(dev,blk);
318 blkBits[chunk/8] |= (1<<(chunk & 7));
321 static Y_INLINE int yaffs_CheckChunkBit(yaffs_Device *dev,int blk,int chunk)
323 __u8 *blkBits = yaffs_BlockBits(dev,blk);
324 return (blkBits[chunk/8] & (1<<(chunk & 7))) ? 1 :0;
327 static Y_INLINE int yaffs_StillSomeChunkBits(yaffs_Device *dev,int blk)
329 __u8 *blkBits = yaffs_BlockBits(dev,blk);
331 for(i = 0; i < dev->chunkBitmapStride; i++)
333 if(*blkBits) return 1;
340 static Y_INLINE int yaffs_HashFunction(int n)
342 return (n % YAFFS_NOBJECT_BUCKETS);
346 yaffs_Object *yaffs_Root(yaffs_Device *dev)
351 yaffs_Object *yaffs_LostNFound(yaffs_Device *dev)
353 return dev->lostNFoundDir;
359 int yaffs_CheckFF(__u8 *buffer,int nBytes)
361 //Horrible, slow implementation
364 if(*buffer != 0xFF) return 0;
370 static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND)
373 int retval = YAFFS_OK;
374 __u8 *data = yaffs_GetTempBuffer(dev,__LINE__);
375 yaffs_ExtendedTags tags;
377 // NCB dev->readChunkWithTagsFromNAND(dev,chunkInNAND,data,&tags);
378 yaffs_ReadChunkWithTagsFromNAND(dev,chunkInNAND,data,&tags);
380 if(!yaffs_CheckFF(data,dev->nBytesPerChunk) || tags.chunkUsed)
382 T(YAFFS_TRACE_NANDACCESS,(TSTR("Chunk %d not erased" TENDSTR),chunkInNAND));
386 yaffs_ReleaseTempBuffer(dev,data,__LINE__);
395 static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, const __u8 *data, yaffs_ExtendedTags *tags,int useReserve)
405 chunk = yaffs_AllocateChunk(dev,useReserve);
410 // First check this chunk is erased...
411 #ifndef CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
412 writeOk = yaffs_CheckChunkErased(dev,chunk);
416 T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs chunk %d was not erased" TENDSTR),chunk));
420 writeOk = yaffs_WriteChunkWithTagsToNAND(dev,chunk,data,tags);
426 // Copy the data into the robustification buffer.
427 // NB We do this at the end to prevent duplicates in the case of a write error.
429 yaffs_HandleWriteChunkOk(dev,chunk,data,tags);
433 yaffs_HandleWriteChunkError(dev,chunk);
437 } while(chunk >= 0 && ! writeOk);
441 T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs write required %d attempts" TENDSTR),attempts));
442 dev->nRetriedWrites+= (attempts - 1);
453 // Functions for robustisizing
457 static void yaffs_RetireBlock(yaffs_Device *dev,int blockInNAND)
460 yaffs_MarkBlockBad(dev,blockInNAND);
462 yaffs_GetBlockInfo(dev,blockInNAND)->blockState = YAFFS_BLOCK_STATE_DEAD;
464 dev->nRetiredBlocks++;
469 static int yaffs_RewriteBufferedBlock(yaffs_Device *dev)
471 dev->doingBufferedBlockRewrite = 1;
473 // Remove erased chunks
474 // Rewrite existing chunks to a new block
475 // Set current write block to the new block
477 dev->doingBufferedBlockRewrite = 0;
483 static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND)
485 int blockInNAND = chunkInNAND/dev->nChunksPerBlock;
487 // Mark the block for retirement
488 yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1;
489 T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>>Block %d marked for retirement" TENDSTR),blockInNAND));
493 // Just do a garbage collection on the affected block then retire the block
498 static void yaffs_CheckWrittenBlock(yaffs_Device *dev,int chunkInNAND)
504 static void yaffs_HandleWriteChunkOk(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *tags)
508 static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND, const yaffs_ExtendedTags *tags)
512 static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND)
514 int blockInNAND = chunkInNAND/dev->nChunksPerBlock;
516 // Mark the block for retirement
517 yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1;
519 yaffs_DeleteChunk(dev,chunkInNAND,1,__LINE__);
525 static int yaffs_VerifyCompare(const __u8 *d0, const __u8 * d1, const yaffs_Spare *s0, const yaffs_Spare *s1,int dataSize)
529 if( memcmp(d0,d1,dataSize) != 0 ||
530 s0->tagByte0 != s1->tagByte0 ||
531 s0->tagByte1 != s1->tagByte1 ||
532 s0->tagByte2 != s1->tagByte2 ||
533 s0->tagByte3 != s1->tagByte3 ||
534 s0->tagByte4 != s1->tagByte4 ||
535 s0->tagByte5 != s1->tagByte5 ||
536 s0->tagByte6 != s1->tagByte6 ||
537 s0->tagByte7 != s1->tagByte7 ||
538 s0->ecc1[0] != s1->ecc1[0] ||
539 s0->ecc1[1] != s1->ecc1[1] ||
540 s0->ecc1[2] != s1->ecc1[2] ||
541 s0->ecc2[0] != s1->ecc2[0] ||
542 s0->ecc2[1] != s1->ecc2[1] ||
543 s0->ecc2[2] != s1->ecc2[2] )
553 ///////////////////////// Object management //////////////////
554 // List of spare objects
555 // The list is hooked together using the first pointer
558 // static yaffs_Object *yaffs_freeObjects = NULL;
560 // static int yaffs_nFreeObjects;
562 // static yaffs_ObjectList *yaffs_allocatedObjectList = NULL;
564 // static yaffs_ObjectBucket yaffs_objectBucket[YAFFS_NOBJECT_BUCKETS];
567 static __u16 yaffs_CalcNameSum(const YCHAR *name)
572 YUCHAR *bname = (YUCHAR *)name;
575 while ((*bname) && (i <=YAFFS_MAX_NAME_LENGTH))
578 #ifdef CONFIG_YAFFS_CASE_INSENSITIVE
579 sum += yaffs_toupper(*bname) * i;
590 void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)
592 #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
593 if(name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH)
595 yaffs_strcpy(obj->shortName,name);
599 obj->shortName[0]=_Y('\0');
602 obj->sum = yaffs_CalcNameSum(name);
606 void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare)
608 yaffs_ECCCalculate(data , spare->ecc1);
609 yaffs_ECCCalculate(&data[256] , spare->ecc2);
614 ///////////////////////// TNODES ///////////////////////
616 // List of spare tnodes
617 // The list is hooked together using the first pointer
620 //static yaffs_Tnode *yaffs_freeTnodes = NULL;
622 // static int yaffs_nFreeTnodes;
624 //static yaffs_TnodeList *yaffs_allocatedTnodeList = NULL;
628 // yaffs_CreateTnodes creates a bunch more tnodes and
629 // adds them to the tnode free list.
630 // Don't use this function directly
632 static int yaffs_CreateTnodes(yaffs_Device *dev,int nTnodes)
635 yaffs_Tnode *newTnodes;
636 yaffs_TnodeList *tnl;
638 if(nTnodes < 1) return YAFFS_OK;
642 newTnodes = YMALLOC(nTnodes * sizeof(yaffs_Tnode));
646 T(YAFFS_TRACE_ERROR,(TSTR("yaffs: Could not allocate Tnodes"TENDSTR)));
650 // Hook them into the free list
651 for(i = 0; i < nTnodes - 1; i++)
653 newTnodes[i].internal[0] = &newTnodes[i+1];
654 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
655 newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = 1;
659 newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes;
660 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
661 newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = 1;
663 dev->freeTnodes = newTnodes;
664 dev->nFreeTnodes+= nTnodes;
665 dev->nTnodesCreated += nTnodes;
667 // Now add this bunch of tnodes to a list for freeing up.
668 // NB If we can't add this to the management list it isn't fatal
669 // but it just means we can't free this bunch of tnodes later.
670 tnl = YMALLOC(sizeof(yaffs_TnodeList));
673 T(YAFFS_TRACE_ERROR,(TSTR("yaffs: Could not add tnodes to management list" TENDSTR)));
678 tnl->tnodes = newTnodes;
679 tnl->next = dev->allocatedTnodeList;
680 dev->allocatedTnodeList = tnl;
684 T(YAFFS_TRACE_ALLOCATE,(TSTR("yaffs: Tnodes added" TENDSTR)));
691 // GetTnode gets us a clean tnode. Tries to make allocate more if we run out
692 static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
694 yaffs_Tnode *tn = NULL;
696 // If there are none left make more
699 yaffs_CreateTnodes(dev,YAFFS_ALLOCATION_NTNODES);
704 tn = dev->freeTnodes;
705 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
706 if(tn->internal[YAFFS_NTNODES_INTERNAL] != 1)
708 // Hoosterman, this thing looks like it isn't in the list
709 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Tnode list bug 1" TENDSTR)));
712 dev->freeTnodes = dev->freeTnodes->internal[0];
715 memset(tn,0,sizeof(yaffs_Tnode));
723 // FreeTnode frees up a tnode and puts it back on the free list
724 static void yaffs_FreeTnode(yaffs_Device*dev, yaffs_Tnode *tn)
728 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
729 if(tn->internal[YAFFS_NTNODES_INTERNAL] != 0)
731 // Hoosterman, this thing looks like it is already in the list
732 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Tnode list bug 2" TENDSTR)));
734 tn->internal[YAFFS_NTNODES_INTERNAL] = 1;
736 tn->internal[0] = dev->freeTnodes;
737 dev->freeTnodes = tn;
743 static void yaffs_DeinitialiseTnodes(yaffs_Device*dev)
745 // Free the list of allocated tnodes
746 yaffs_TnodeList *tmp;
748 while(dev->allocatedTnodeList)
750 tmp = dev->allocatedTnodeList->next;
752 YFREE(dev->allocatedTnodeList->tnodes);
753 YFREE(dev->allocatedTnodeList);
754 dev->allocatedTnodeList = tmp;
758 dev->freeTnodes = NULL;
759 dev->nFreeTnodes = 0;
762 static void yaffs_InitialiseTnodes(yaffs_Device*dev)
764 dev->allocatedTnodeList = NULL;
765 dev->freeTnodes = NULL;
766 dev->nFreeTnodes = 0;
767 dev->nTnodesCreated = 0;
772 void yaffs_TnodeTest(yaffs_Device *dev)
777 yaffs_Tnode *tn[1000];
779 YINFO("Testing TNodes");
781 for(j = 0; j < 50; j++)
783 for(i = 0; i < 1000; i++)
785 tn[i] = yaffs_GetTnode(dev);
788 YALERT("Getting tnode failed");
791 for(i = 0; i < 1000; i+=3)
793 yaffs_FreeTnode(dev,tn[i]);
802 ////////////////// END OF TNODE MANIPULATION ///////////////////////////
804 /////////////// Functions to manipulate the look-up tree (made up of tnodes)
805 // The look up tree is represented by the top tnode and the number of topLevel
806 // in the tree. 0 means only the level 0 tnode is in the tree.
809 // FindLevel0Tnode finds the level 0 tnode, if one exists.
810 // Used when reading.....
811 static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,yaffs_FileStructure *fStruct, __u32 chunkId)
814 yaffs_Tnode *tn = fStruct->top;
816 int requiredTallness;
817 int level = fStruct->topLevel;
819 // Check sane level and chunk Id
820 if(level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
823 // sprintf(str,"Bad level %d",level);
828 if(chunkId > YAFFS_MAX_CHUNK_ID)
831 // sprintf(str,"Bad chunkId %d",chunkId);
836 // First check we're tall enough (ie enough topLevel)
838 i = chunkId >> (/*dev->chunkGroupBits + */YAFFS_TNODES_LEVEL0_BITS);
839 requiredTallness = 0;
842 i >>= YAFFS_TNODES_INTERNAL_BITS;
847 if(requiredTallness > fStruct->topLevel)
849 // Not tall enough, so we can't find it, return NULL.
854 // Traverse down to level 0
855 while (level > 0 && tn)
857 tn = tn->internal[(chunkId >>(/* dev->chunkGroupBits + */ YAFFS_TNODES_LEVEL0_BITS + (level-1) * YAFFS_TNODES_INTERNAL_BITS)) &
858 YAFFS_TNODES_INTERNAL_MASK];
866 // AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
867 // This happens in two steps:
868 // 1. If the tree isn't tall enough, then make it taller.
869 // 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
871 // Used when modifying the tree.
873 static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, yaffs_FileStructure *fStruct, __u32 chunkId)
878 int requiredTallness;
885 //T((TSTR("AddOrFind topLevel=%d, chunk=%d"),fStruct->topLevel,chunkId));
887 // Check sane level and page Id
888 if(fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL)
891 // sprintf(str,"Bad level %d",fStruct->topLevel);
896 if(chunkId > YAFFS_MAX_CHUNK_ID)
899 // sprintf(str,"Bad chunkId %d",chunkId);
904 // First check we're tall enough (ie enough topLevel)
906 x = chunkId >> (/*dev->chunkGroupBits + */YAFFS_TNODES_LEVEL0_BITS);
907 requiredTallness = 0;
910 x >>= YAFFS_TNODES_INTERNAL_BITS;
914 //T((TSTR(" required=%d"),requiredTallness));
917 if(requiredTallness > fStruct->topLevel)
919 // Not tall enough,gotta make the tree taller
920 for(i = fStruct->topLevel; i < requiredTallness; i++)
922 //T((TSTR(" add new top")));
924 tn = yaffs_GetTnode(dev);
928 tn->internal[0] = fStruct->top;
933 T(YAFFS_TRACE_ERROR,(TSTR("yaffs: no more tnodes" TENDSTR)));
937 fStruct->topLevel = requiredTallness;
941 // Traverse down to level 0, adding anything we need
943 l = fStruct->topLevel;
947 x = (chunkId >> (/*dev->chunkGroupBits + */YAFFS_TNODES_LEVEL0_BITS + (l-1) * YAFFS_TNODES_INTERNAL_BITS)) &
948 YAFFS_TNODES_INTERNAL_MASK;
950 //T((TSTR(" [%d:%d]"),l,i));
954 //T((TSTR(" added")));
956 tn->internal[x] = yaffs_GetTnode(dev);
959 tn = tn->internal[x];
970 int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk, yaffs_ExtendedTags *tags, int objectId, int chunkInInode)
975 for(j = 0; theChunk && j < dev->chunkGroupSize; j++)
977 if(yaffs_CheckChunkBit(dev,theChunk / dev->nChunksPerBlock,theChunk % dev->nChunksPerBlock))
979 yaffs_ReadChunkWithTagsFromNAND(dev,theChunk,NULL,tags);
980 if(yaffs_TagsMatch(tags,objectId,chunkInInode))
992 // DeleteWorker scans backwards through the tnode tree and deletes all the
993 // chunks and tnodes in the file
994 // Returns 1 if the tree was deleted. Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
996 static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset,int *limit)
1001 yaffs_ExtendedTags tags;
1003 yaffs_Device *dev = in->myDev;
1013 for(i = YAFFS_NTNODES_INTERNAL -1; allDone && i >= 0; i--)
1017 if(limit && (*limit) < 0)
1023 allDone = yaffs_DeleteWorker(in,tn->internal[i],level - 1,
1024 (chunkOffset << YAFFS_TNODES_INTERNAL_BITS ) + i ,limit);
1028 yaffs_FreeTnode(dev,tn->internal[i]);
1029 tn->internal[i] = NULL;
1034 return (allDone) ? 1 : 0;
1040 for(i = YAFFS_NTNODES_LEVEL0 -1; i >= 0 && !hitLimit; i--)
1045 chunkInInode = (chunkOffset << YAFFS_TNODES_LEVEL0_BITS ) + i;
1047 theChunk = tn->level0[i] << dev->chunkGroupBits;
1049 foundChunk = yaffs_FindChunkInGroup(dev,theChunk,&tags,in->objectId,chunkInInode);
1053 yaffs_DeleteChunk(dev,foundChunk,1,__LINE__);
1070 return (i < 0) ? 1 : 0;
1082 static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk)
1085 yaffs_BlockInfo *theBlock;
1087 T(YAFFS_TRACE_DELETION,(TSTR("soft delete chunk %d" TENDSTR),chunk));
1089 theBlock = yaffs_GetBlockInfo(dev, chunk/dev->nChunksPerBlock);
1092 theBlock->softDeletions++;
1096 // SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
1097 // All soft deleting does is increment the block's softdelete count and pulls the chunk out
1099 // THus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
1101 static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset)
1106 yaffs_Device *dev = in->myDev;
1114 for(i = YAFFS_NTNODES_INTERNAL -1; allDone && i >= 0; i--)
1118 allDone = yaffs_SoftDeleteWorker(in,tn->internal[i],level - 1,
1119 (chunkOffset << YAFFS_TNODES_INTERNAL_BITS ) + i);
1122 yaffs_FreeTnode(dev,tn->internal[i]);
1123 tn->internal[i] = NULL;
1127 //Hoosterman... how could this happen.
1131 return (allDone) ? 1 : 0;
1136 for(i = YAFFS_NTNODES_LEVEL0 -1; i >=0; i--)
1140 // Note this does not find the real chunk, only the chunk group.
1141 // We make an assumption that a chunk group is niot larger than a block.
1142 theChunk = (tn->level0[i] << dev->chunkGroupBits);
1144 yaffs_SoftDeleteChunk(dev,theChunk);
1161 static void yaffs_SoftDeleteFile(yaffs_Object *obj)
1164 obj->variantType == YAFFS_OBJECT_TYPE_FILE &&
1167 if(obj->nDataChunks <= 0)
1169 // Empty file with no duplicate object headers, just delete it immediately
1170 yaffs_FreeTnode(obj->myDev,obj->variant.fileVariant.top);
1171 obj->variant.fileVariant.top = NULL;
1172 T(YAFFS_TRACE_TRACING,(TSTR("yaffs: Deleting empty file %d" TENDSTR),obj->objectId));
1173 yaffs_DoGenericObjectDeletion(obj);
1177 yaffs_SoftDeleteWorker(obj, obj->variant.fileVariant.top, obj->variant.fileVariant.topLevel, 0);
1178 obj->softDeleted = 1;
1187 // Pruning removes any part of the file structure tree that is beyond the
1188 // bounds of the file (ie that does not point to chunks).
1190 // A file should only get pruned when its size is reduced.
1192 // Before pruning, the chunks must be pulled from the tree and the
1193 // level 0 tnode entries must be zeroed out.
1194 // Could also use this for file deletion, but that's probably better handled
1195 // by a special case.
1197 // yaffs_PruneWorker should only be called by yaffs_PruneFileStructure()
1199 static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn, __u32 level, int del0)
1208 for(i = 0; i < YAFFS_NTNODES_INTERNAL; i++)
1210 if(tn->internal[i] && level > 0)
1212 tn->internal[i] = yaffs_PruneWorker(dev,tn->internal[i],level - 1, ( i == 0) ? del0 : 1);
1221 if(hasData == 0 && del0)
1223 // Free and return NULL
1225 yaffs_FreeTnode(dev,tn);
1235 static int yaffs_PruneFileStructure(yaffs_Device *dev, yaffs_FileStructure *fStruct)
1242 if(fStruct->topLevel > 0)
1244 fStruct->top = yaffs_PruneWorker(dev,fStruct->top, fStruct->topLevel,0);
1246 // Now we have a tree with all the non-zero branches NULL but the height
1247 // is the same as it was.
1248 // Let's see if we can trim internal tnodes to shorten the tree.
1249 // We can do this if only the 0th element in the tnode is in use
1250 // (ie all the non-zero are NULL)
1252 while(fStruct->topLevel && !done)
1257 for(i = 1; i <YAFFS_NTNODES_INTERNAL; i++)
1267 fStruct->top = tn->internal[0];
1268 fStruct->topLevel--;
1269 yaffs_FreeTnode(dev,tn);
1285 /////////////////////// End of File Structure functions. /////////////////
1287 // yaffs_CreateFreeObjects creates a bunch more objects and
1288 // adds them to the object free list.
1289 static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
1292 yaffs_Object *newObjects;
1293 yaffs_ObjectList *list;
1295 if(nObjects < 1) return YAFFS_OK;
1297 // make these things
1299 newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
1303 T(YAFFS_TRACE_ALLOCATE,(TSTR("yaffs: Could not allocate more objects" TENDSTR)));
1307 // Hook them into the free list
1308 for(i = 0; i < nObjects - 1; i++)
1310 newObjects[i].siblings.next = (struct list_head *)(&newObjects[i+1]);
1313 newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects;
1314 dev->freeObjects = newObjects;
1315 dev->nFreeObjects+= nObjects;
1316 dev->nObjectsCreated+= nObjects;
1318 // Now add this bunch of Objects to a list for freeing up.
1320 list = YMALLOC(sizeof(yaffs_ObjectList));
1323 T(YAFFS_TRACE_ALLOCATE,(TSTR("Could not add objects to management list" TENDSTR)));
1327 list->objects = newObjects;
1328 list->next = dev->allocatedObjectList;
1329 dev->allocatedObjectList = list;
1338 // AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out
1339 static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev)
1341 yaffs_Object *tn = NULL;
1343 // If there are none left make more
1344 if(!dev->freeObjects)
1346 yaffs_CreateFreeObjects(dev,YAFFS_ALLOCATION_NOBJECTS);
1349 if(dev->freeObjects)
1351 tn = dev->freeObjects;
1352 dev->freeObjects = (yaffs_Object *)(dev->freeObjects->siblings.next);
1353 dev->nFreeObjects--;
1355 // Now sweeten it up...
1357 memset(tn,0,sizeof(yaffs_Object));
1360 tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
1361 INIT_LIST_HEAD(&(tn->hardLinks));
1362 INIT_LIST_HEAD(&(tn->hashLink));
1363 INIT_LIST_HEAD(&tn->siblings);
1365 // Add it to the lost and found directory.
1366 // NB Can't put root or lostNFound in lostNFound so
1367 // check if lostNFound exists first
1368 if(dev->lostNFoundDir)
1370 yaffs_AddObjectToDirectory(dev->lostNFoundDir,tn);
1378 static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev,int number,__u32 mode)
1381 yaffs_Object *obj = yaffs_CreateNewObject(dev,number,YAFFS_OBJECT_TYPE_DIRECTORY);
1384 obj->fake = 1; // it is fake so it has no NAND presence...
1385 obj->renameAllowed= 0; // ... and we're not allowed to rename it...
1386 obj->unlinkAllowed= 0; // ... or unlink it
1389 obj->st_mode = mode;
1391 obj->chunkId = 0; // Not a valid chunk.
1399 static void yaffs_UnhashObject(yaffs_Object *tn)
1402 yaffs_Device *dev = tn->myDev;
1405 // If it is still linked into the bucket list, free from the list
1406 if(!list_empty(&tn->hashLink))
1408 list_del_init(&tn->hashLink);
1409 bucket = yaffs_HashFunction(tn->objectId);
1410 dev->objectBucket[bucket].count--;
1416 // FreeObject frees up a Object and puts it back on the free list
1417 static void yaffs_FreeObject(yaffs_Object *tn)
1420 yaffs_Device *dev = tn->myDev;
1425 // We're still hooked up to a cached inode.
1426 // Don't delete now, but mark for later deletion
1427 tn->deferedFree = 1;
1432 yaffs_UnhashObject(tn);
1434 // Link into the free list.
1435 tn->siblings.next = (struct list_head *)(dev->freeObjects);
1436 dev->freeObjects = tn;
1437 dev->nFreeObjects++;
1444 void yaffs_HandleDeferedFree(yaffs_Object *obj)
1446 if(obj->deferedFree)
1448 yaffs_FreeObject(obj);
1456 static void yaffs_DeinitialiseObjects(yaffs_Device *dev)
1458 // Free the list of allocated Objects
1460 yaffs_ObjectList *tmp;
1462 while( dev->allocatedObjectList)
1464 tmp = dev->allocatedObjectList->next;
1465 YFREE(dev->allocatedObjectList->objects);
1466 YFREE(dev->allocatedObjectList);
1468 dev->allocatedObjectList = tmp;
1471 dev->freeObjects = NULL;
1472 dev->nFreeObjects = 0;
1475 static void yaffs_InitialiseObjects(yaffs_Device *dev)
1479 dev->allocatedObjectList = NULL;
1480 dev->freeObjects = NULL;
1481 dev->nFreeObjects = 0;
1483 for(i = 0; i < YAFFS_NOBJECT_BUCKETS; i++)
1485 INIT_LIST_HEAD(&dev->objectBucket[i].list);
1486 dev->objectBucket[i].count = 0;
1496 int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
1501 int lowest = 999999;
1504 // First let's see if we can find one that's empty.
1506 for(i = 0; i < 10 && lowest > 0; i++)
1509 x %= YAFFS_NOBJECT_BUCKETS;
1510 if(dev->objectBucket[x].count < lowest)
1512 lowest = dev->objectBucket[x].count;
1518 // If we didn't find an empty list, then try
1519 // looking a bit further for a short one
1521 for(i = 0; i < 10 && lowest > 3; i++)
1524 x %= YAFFS_NOBJECT_BUCKETS;
1525 if(dev->objectBucket[x].count < lowest)
1527 lowest = dev->objectBucket[x].count;
1536 static int yaffs_CreateNewObjectNumber(yaffs_Device *dev)
1538 int bucket = yaffs_FindNiceObjectBucket(dev);
1540 // Now find an object value that has not already been taken
1541 // by scanning the list.
1544 struct list_head *i;
1546 __u32 n = (__u32)bucket;
1548 //yaffs_CheckObjectHashSanity();
1553 n += YAFFS_NOBJECT_BUCKETS;
1554 if(1 ||dev->objectBucket[bucket].count > 0)
1556 list_for_each(i,&dev->objectBucket[bucket].list)
1558 // If there is already one in the list
1559 if(i && list_entry(i, yaffs_Object,hashLink)->objectId == n)
1567 //T(("bucket %d count %d inode %d\n",bucket,yaffs_objectBucket[bucket].count,n);
1572 void yaffs_HashObject(yaffs_Object *in)
1574 int bucket = yaffs_HashFunction(in->objectId);
1575 yaffs_Device *dev = in->myDev;
1577 if(!list_empty(&in->hashLink))
1583 list_add(&in->hashLink,&dev->objectBucket[bucket].list);
1584 dev->objectBucket[bucket].count++;
1588 yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev,__u32 number)
1590 int bucket = yaffs_HashFunction(number);
1591 struct list_head *i;
1594 list_for_each(i,&dev->objectBucket[bucket].list)
1596 // Look if it is in the list
1599 in = list_entry(i, yaffs_Object,hashLink);
1600 if(in->objectId == number)
1603 // Don't tell the VFS about this one if it is defered free
1618 yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type)
1621 yaffs_Object *theObject;
1625 number = yaffs_CreateNewObjectNumber(dev);
1628 theObject = yaffs_AllocateEmptyObject(dev);
1632 theObject->fake = 0;
1633 theObject->renameAllowed = 1;
1634 theObject->unlinkAllowed = 1;
1635 theObject->objectId = number;
1636 yaffs_HashObject(theObject);
1637 theObject->variantType = type;
1638 #ifdef CONFIG_YAFFS_WINCE
1639 yfsd_WinFileTimeNow(theObject->win_atime);
1640 theObject->win_ctime[0] = theObject->win_mtime[0] = theObject->win_atime[0];
1641 theObject->win_ctime[1] = theObject->win_mtime[1] = theObject->win_atime[1];
1645 theObject->st_atime = theObject->st_mtime = theObject->st_ctime = Y_CURRENT_TIME;
1649 case YAFFS_OBJECT_TYPE_FILE:
1650 theObject->variant.fileVariant.fileSize = 0;
1651 theObject->variant.fileVariant.scannedFileSize = 0;
1652 theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; // max __u32
1653 theObject->variant.fileVariant.topLevel = 0;
1654 theObject->variant.fileVariant.top = yaffs_GetTnode(dev);
1656 case YAFFS_OBJECT_TYPE_DIRECTORY:
1657 INIT_LIST_HEAD(&theObject->variant.directoryVariant.children);
1659 case YAFFS_OBJECT_TYPE_SYMLINK:
1660 // No action required
1662 case YAFFS_OBJECT_TYPE_HARDLINK:
1663 // No action required
1665 case YAFFS_OBJECT_TYPE_SPECIAL:
1666 // No action required
1668 case YAFFS_OBJECT_TYPE_UNKNOWN:
1669 // todo this should not happen
1677 yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, int number,yaffs_ObjectType type)
1679 yaffs_Object *theObject = NULL;
1683 theObject = yaffs_FindObjectByNumber(dev,number);
1688 theObject = yaffs_CreateNewObject(dev,number,type);
1695 YCHAR *yaffs_CloneString(const YCHAR *str)
1697 YCHAR *newStr = NULL;
1701 newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR));
1702 yaffs_strcpy(newStr,str);
1710 // Mknod (create) a new object.
1711 // equivalentObject only has meaning for a hard link;
1712 // aliasString only has meaning for a sumlink.
1713 // rdev only has meaning for devices (a subset of special objects)
1714 yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type,
1715 yaffs_Object *parent,
1720 yaffs_Object *equivalentObject,
1721 const YCHAR *aliasString,
1726 yaffs_Device *dev = parent->myDev;
1728 // Check if the entry exists. If it does then fail the call since we don't want a dup.
1729 if(yaffs_FindObjectByName(parent,name))
1734 in = yaffs_CreateNewObject(dev,-1,type);
1740 in->variantType = type;
1744 #ifdef CONFIG_YAFFS_WINCE
1745 yfsd_WinFileTimeNow(in->win_atime);
1746 in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];
1747 in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
1750 in->st_atime = in->st_mtime = in->st_ctime = Y_CURRENT_TIME;
1756 in->nDataChunks = 0;
1758 yaffs_SetObjectName(in,name);
1761 yaffs_AddObjectToDirectory(parent,in);
1763 in->myDev = parent->myDev;
1768 case YAFFS_OBJECT_TYPE_SYMLINK:
1769 in->variant.symLinkVariant.alias = yaffs_CloneString(aliasString);
1771 case YAFFS_OBJECT_TYPE_HARDLINK:
1772 in->variant.hardLinkVariant.equivalentObject = equivalentObject;
1773 in->variant.hardLinkVariant.equivalentObjectId = equivalentObject->objectId;
1774 list_add(&in->hardLinks,&equivalentObject->hardLinks);
1776 case YAFFS_OBJECT_TYPE_FILE: // do nothing
1777 case YAFFS_OBJECT_TYPE_DIRECTORY: // do nothing
1778 case YAFFS_OBJECT_TYPE_SPECIAL: // do nothing
1779 case YAFFS_OBJECT_TYPE_UNKNOWN:
1783 if(/*yaffs_GetNumberOfFreeChunks(dev) <= 0 || */
1784 yaffs_UpdateObjectHeader(in,name,0,0) < 0)
1786 // Could not create the object header, fail the creation
1787 yaffs_DestroyObject(in);
1796 yaffs_Object *yaffs_MknodFile(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid)
1798 return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE,parent,name,mode,uid,gid,NULL,NULL,0);
1801 yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid)
1803 return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY,parent,name,mode,uid,gid,NULL,NULL,0);
1806 yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid, __u32 rdev)
1808 return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL,parent,name,mode,uid,gid,NULL,NULL,rdev);
1811 yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid,const YCHAR *alias)
1813 return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK,parent,name,mode,uid,gid,NULL,alias,0);
1816 // NB yaffs_Link returns the object id of the equivalent object.
1817 yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name, yaffs_Object *equivalentObject)
1819 // Get the real object in case we were fed a hard link as an equivalent object
1820 equivalentObject = yaffs_GetEquivalentObject(equivalentObject);
1822 if(yaffs_MknodObject(YAFFS_OBJECT_TYPE_HARDLINK,parent,name,0,0,0,equivalentObject,NULL,0))
1824 return equivalentObject;
1834 static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const YCHAR *newName,int force)
1841 newDir = obj->parent; // use the old directory
1844 if(newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
1846 T(YAFFS_TRACE_ALWAYS,(TSTR("tragendy: yaffs_ChangeObjectName: newDir is not a directory"TENDSTR)));
1850 // TODO: Do we need this different handling for YAFFS2 and YAFFS1??
1851 if(obj->myDev->isYaffs2)
1853 unlinkOp = (newDir == obj->myDev->unlinkedDir);
1857 unlinkOp = (newDir == obj->myDev->unlinkedDir && obj->variantType == YAFFS_OBJECT_TYPE_FILE);
1860 deleteOp = (newDir == obj->myDev->deletedDir);
1862 // If the object is a file going into the unlinked directory, then it is OK to just stuff it in since
1863 // duplicate names are allowed.
1864 // Otherwise only proceed if the new name does not exist and if we're putting it into a directory.
1868 !yaffs_FindObjectByName(newDir,newName)) &&
1869 newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
1871 yaffs_SetObjectName(obj,newName);
1874 yaffs_AddObjectToDirectory(newDir,obj);
1876 if(unlinkOp) obj->unlinked = 1;
1878 // If it is a deletion then we mark it as a shrink for gc purposes.
1879 if(yaffs_UpdateObjectHeader(obj,newName,0,deleteOp) >= 0)
1890 int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName, yaffs_Object *newDir, const YCHAR *newName)
1895 #ifdef CONFIG_YAFFS_CASE_INSENSITIVE
1896 // Special case for case insemsitive systems (eg. WinCE).
1897 // While look-up is case insensitive, the name isn't.
1898 // THerefore we might want to change x.txt to X.txt
1899 if(oldDir == newDir && yaffs_strcmp(oldName,newName) == 0)
1905 obj = yaffs_FindObjectByName(oldDir,oldName);
1906 if(obj && obj->renameAllowed)
1908 return yaffs_ChangeObjectName(obj,newDir,newName,force);
1916 static int yaffs_CheckObjectHashSanity(yaffs_Device *dev)
1918 // Scan the buckets and check that the lists
1919 // have as many members as the count says there are
1922 struct list_head *j;
1925 for(bucket = 0; bucket < YAFFS_NOBJECT_BUCKETS; bucket++)
1929 list_for_each(j,&dev->objectBucket[bucket].list)
1934 if(countEm != dev->objectBucket[bucket].count)
1936 T(YAFFS_TRACE_ERROR,(TSTR("Inode hash inconsistency" TENDSTR)));
1945 void yaffs_ObjectTest(yaffs_Device *dev)
1947 yaffs_Object *in[1000];
1949 yaffs_Object *inold[1000];
1953 memset(in,0,1000*sizeof(yaffs_Object *));
1954 memset(inold,0,1000*sizeof(yaffs_Object *));
1956 yaffs_CheckObjectHashSanity(dev);
1958 for(j = 0; j < 10; j++)
1962 for(i = 0; i < 1000; i++)
1964 in[i] = yaffs_CreateNewObject(dev,-1,YAFFS_OBJECT_TYPE_FILE);
1967 YINFO("No more inodes");
1971 inNo[i] = in[i]->objectId;
1975 for(i = 0; i < 1000; i++)
1977 if(yaffs_FindObjectByNumber(dev,inNo[i]) != in[i])
1979 //T(("Differnce in look up test\n"));
1983 // T(("Look up ok\n"));
1987 yaffs_CheckObjectHashSanity(dev);
1989 for(i = 0; i < 1000; i+=3)
1991 yaffs_FreeObject(in[i]);
1996 yaffs_CheckObjectHashSanity(dev);
2003 /////////////////////////// Block Management and Page Allocation ///////////////////
2006 static int yaffs_InitialiseBlocks(yaffs_Device *dev,int nBlocks)
2008 dev->allocationBlock = -1; // force it to get a new one
2009 //Todo we're assuming the malloc will pass.
2010 dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo));
2011 // Set up dynamic blockinfo stuff.
2012 dev->chunkBitmapStride = (dev->nChunksPerBlock+7)/8;
2013 dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks);
2014 if(dev->blockInfo && dev->chunkBits)
2016 memset(dev->blockInfo,0,nBlocks * sizeof(yaffs_BlockInfo));
2017 memset(dev->chunkBits,0,dev->chunkBitmapStride * nBlocks);
2025 static void yaffs_DeinitialiseBlocks(yaffs_Device *dev)
2027 YFREE(dev->blockInfo);
2028 dev->blockInfo = NULL;
2029 YFREE(dev->chunkBits);
2030 dev->chunkBits = NULL;
2034 static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device *dev, yaffs_BlockInfo *bi)
2040 if(!dev->isYaffs2) return 1; // disqualification only applies to yaffs2.
2042 if(!bi->hasShrinkHeader) return 1; // can gc
2045 // Find the oldest dirty sequence number if we don't know it and save it
2046 // so we don't have to keep recomputing it.
2047 if(!dev->oldestDirtySequence)
2049 seq = dev->sequenceNumber;
2051 for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++)
2053 b = yaffs_GetBlockInfo(dev,i);
2054 if(b->blockState == YAFFS_BLOCK_STATE_FULL &&
2055 (b->pagesInUse - b->softDeletions )< dev->nChunksPerBlock &&
2056 b->sequenceNumber < seq)
2058 seq = b->sequenceNumber;
2061 dev->oldestDirtySequence = seq;
2065 // Can't do gc of this block if there are any blocks older than this one that have
2067 return (bi->sequenceNumber <= dev->oldestDirtySequence);
2074 // FindDiretiestBlock is used to select the dirtiest block (or close enough)
2075 // for garbage collection.
2080 static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,int aggressive)
2083 int b = dev->currentDirtyChecker;
2089 yaffs_BlockInfo *bi;
2090 static int nonAggressiveSkip = 0;
2092 // If we're doing aggressive GC then we are happy to take a less-dirty block, and
2094 // else (we're doing a leasurely gc), then we only bother to do this if the
2095 // block has only a few pages in use.
2098 nonAggressiveSkip--;
2100 if(!aggressive &&(nonAggressiveSkip > 0))
2105 pagesInUse = (aggressive)? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1;
2108 iterations = dev->internalEndBlock - dev->internalStartBlock + 1;
2112 iterations = dev->internalEndBlock - dev->internalStartBlock + 1;
2113 iterations = iterations / 16;
2114 if(iterations > 200)
2120 for(i = 0; i <= iterations && pagesInUse > 0 ; i++)
2123 if ( b < dev->internalStartBlock || b > dev->internalEndBlock)
2125 b = dev->internalStartBlock;
2128 if(b < dev->internalStartBlock || b > dev->internalEndBlock)
2130 T(YAFFS_TRACE_ERROR,(TSTR("**>> Block %d is not valid" TENDSTR),b));
2134 bi = yaffs_GetBlockInfo(dev,b);
2136 if(bi->blockState == YAFFS_BLOCK_STATE_FULL &&
2137 (bi->pagesInUse - bi->softDeletions )< pagesInUse &&
2138 yaffs_BlockNotDisqualifiedFromGC(dev,bi))
2141 pagesInUse = (bi->pagesInUse - bi->softDeletions);
2145 dev->currentDirtyChecker = b;
2149 T(YAFFS_TRACE_GC,(TSTR("GC Selected block %d with %d free" TENDSTR),dirtiest,dev->nChunksPerBlock - pagesInUse));
2152 dev->oldestDirtySequence = 0; // clear this
2156 nonAggressiveSkip = 4;
2163 static void yaffs_BlockBecameDirty(yaffs_Device *dev,int blockNo)
2165 yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,blockNo);
2169 // If the block is still healthy erase it and mark as clean.
2170 // If the block has had a data failure, then retire it.
2171 bi->blockState = YAFFS_BLOCK_STATE_DIRTY;
2173 if(!bi->needsRetiring)
2175 erasedOk = yaffs_EraseBlockInNAND(dev,blockNo);
2178 dev->nErasureFailures++;
2179 T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>> Erasure failed %d" TENDSTR),blockNo));
2183 if(erasedOk && (yaffs_traceMask & YAFFS_TRACE_ERASE))
2186 for(i = 0; i < dev->nChunksPerBlock; i++)
2188 if(!yaffs_CheckChunkErased(dev,blockNo * dev->nChunksPerBlock + i))
2190 T(YAFFS_TRACE_ERROR,(TSTR(">>Block %d erasure supposedly OK, but chunk %d not erased" TENDSTR),blockNo,i));
2198 bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
2199 dev->nErasedBlocks++;
2201 bi->softDeletions = 0;
2202 bi->hasShrinkHeader=0;
2203 yaffs_ClearChunkBits(dev,blockNo);
2205 T(YAFFS_TRACE_ERASE,(TSTR("Erased block %d" TENDSTR),blockNo));
2209 yaffs_RetireBlock(dev,blockNo);
2210 T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>> Block %d retired" TENDSTR),blockNo));
2215 static void yaffs_DumpBlockStats(yaffs_Device *dev)
2218 yaffs_BlockInfo *bi;
2220 for(i= dev->internalStartBlock; i <=dev->internalEndBlock; i++)
2222 bi = yaffs_GetBlockInfo(dev,i);
2223 T(YAFFS_TRACE_ALLOCATE,(TSTR("%3d state %d shrink %d inuse %d/%d seq %d pages"),i,
2224 bi->blockState,bi->hasShrinkHeader,bi->pagesInUse,bi->softDeletions,bi->sequenceNumber));
2226 for(j = 0; j < dev->nChunksPerBlock; j++)
2228 if(yaffs_CheckChunkBit(dev,i,j))
2230 T(YAFFS_TRACE_ALLOCATE,(TSTR(" %d"),j));
2234 T(YAFFS_TRACE_ALLOCATE,(TSTR(" " TENDSTR)));
2241 static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
2245 yaffs_BlockInfo *bi;
2250 if(j < 0 || j > 100)
2253 yaffs_DumpBlockStats(dev);
2258 if(dev->nErasedBlocks < 1)
2260 // Hoosterman we've got a problem.
2261 // Can't get space to gc
2262 T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: no more eraased blocks" TENDSTR)));
2267 // Find an empty block.
2269 for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++)
2271 dev->allocationBlockFinder++;
2272 if(dev->allocationBlockFinder < dev->internalStartBlock || dev->allocationBlockFinder> dev->internalEndBlock)
2274 dev->allocationBlockFinder = dev->internalStartBlock;
2277 bi = yaffs_GetBlockInfo(dev,dev->allocationBlockFinder);
2279 if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
2281 bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING;
2282 dev->sequenceNumber++;
2283 bi->sequenceNumber = dev->sequenceNumber;
2284 dev->nErasedBlocks--;
2285 T(YAFFS_TRACE_ALLOCATE,(TSTR("Allocated block %d, seq %d, %d left" TENDSTR),dev->allocationBlockFinder,dev->sequenceNumber, dev->nErasedBlocks));
2286 return dev->allocationBlockFinder;
2291 T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs tragedy: no more eraased blocks, but there should have been %d" TENDSTR),dev->nErasedBlocks));
2302 static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve)
2305 yaffs_BlockInfo *bi;
2307 if(dev->allocationBlock < 0)
2309 // Get next block to allocate off
2310 dev->allocationBlock = yaffs_FindBlockForAllocation(dev);
2311 dev->allocationPage = 0;
2314 if(!useReserve && dev->nErasedBlocks </*=*/ dev->nReservedBlocks)
2316 // Not enough space to allocate unless we're allowed to use the reserve.
2320 if(dev->nErasedBlocks < dev->nReservedBlocks && dev->allocationPage == 0)
2322 T(YAFFS_TRACE_ALLOCATE,(TSTR("Allocating reserve" TENDSTR)));
2326 // Next page please....
2327 if(dev->allocationBlock >= 0)
2329 bi = yaffs_GetBlockInfo(dev,dev->allocationBlock);
2331 retVal = (dev->allocationBlock * dev->nChunksPerBlock) +
2332 dev->allocationPage;
2334 yaffs_SetChunkBit(dev,dev->allocationBlock,dev->allocationPage);
2336 dev->allocationPage++;
2340 // If the block is full set the state to full
2341 if(dev->allocationPage >= dev->nChunksPerBlock)
2343 bi->blockState = YAFFS_BLOCK_STATE_FULL;
2344 dev->allocationBlock = -1;
2351 T(YAFFS_TRACE_ERROR,(TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));
2357 // To determine if we have enough space we just look at the
2358 // number of erased blocks.
2359 // The cache is allowed to use reserved blocks.
2361 static int yaffs_CheckSpaceForChunkCache(yaffs_Device *dev)
2363 return (dev->nErasedBlocks >= dev->nReservedBlocks);
2367 static int yaffs_GetErasedChunks(yaffs_Device *dev)
2371 n = dev->nErasedBlocks * dev->nChunksPerBlock;
2373 if(dev->allocationBlock> 0)
2375 n += (dev->nChunksPerBlock - dev->allocationPage);
2382 int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
2388 int retVal = YAFFS_OK;
2392 int chunksBefore = yaffs_GetErasedChunks(dev);
2395 yaffs_ExtendedTags tags;
2397 yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,block);
2399 yaffs_Object *object;
2401 bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
2403 T(YAFFS_TRACE_TRACING,(TSTR("Collecting block %d, in use %d, shrink %d, " TENDSTR),block,bi->pagesInUse,bi->hasShrinkHeader));
2404 //T(("Collecting block %d n %d bits %x\n",block, bi->pagesInUse, bi->pageBits));
2406 bi->hasShrinkHeader = 0; // clear the flag so that the block can erase
2409 if(!yaffs_StillSomeChunkBits(dev,block))
2411 T(YAFFS_TRACE_TRACING,(TSTR("Collecting block %d that has no chunks in use" TENDSTR),block));
2412 yaffs_BlockBecameDirty(dev,block);
2417 __u8 *buffer = yaffs_GetTempBuffer(dev,__LINE__);
2419 for(chunkInBlock = 0,oldChunk = block * dev->nChunksPerBlock;
2420 chunkInBlock < dev->nChunksPerBlock && yaffs_StillSomeChunkBits(dev,block);
2421 chunkInBlock++, oldChunk++ )
2423 if(yaffs_CheckChunkBit(dev,block,chunkInBlock))
2426 // This page is in use and might need to be copied off
2430 //T(("copying page %x from %d to %d\n",mask,oldChunk,newChunk));
2432 yaffs_InitialiseTags(&tags);
2434 yaffs_ReadChunkWithTagsFromNAND(dev,oldChunk,buffer, &tags);
2436 object = yaffs_FindObjectByNumber(dev,tags.objectId);
2438 T(YAFFS_TRACE_GC_DETAIL,(TSTR("Collecting page %d, %d %d %d " TENDSTR),chunkInBlock,tags.objectId,tags.chunkId,tags.byteCount));
2442 T(YAFFS_TRACE_ERROR,(TSTR("page %d in gc has no object " TENDSTR),oldChunk));
2445 if(object && object->deleted && tags.chunkId != 0)
2447 // Data chunk in a deleted file, throw it away
2448 // It's a deleted data chunk,
2449 // No need to copy this, just forget about it and fix up the
2452 //yaffs_PutChunkIntoFile(object, tags.chunkId, 0,0);
2453 object->nDataChunks--;
2455 if(object->nDataChunks <= 0)
2457 // remeber to clean up the object
2458 dev->gcCleanupList[cleanups] = tags.objectId;
2463 else if( 0 /* Todo object && object->deleted && object->nDataChunks == 0 */)
2465 // Deleted object header with no data chunks.
2466 // Can be discarded and the file deleted.
2467 object->chunkId = 0;
2468 yaffs_FreeTnode(object->myDev,object->variant.fileVariant.top);
2469 object->variant.fileVariant.top = NULL;
2470 yaffs_DoGenericObjectDeletion(object);
2475 // It's either a data chunk in a live file or
2476 // an ObjectHeader, so we're interested in it.
2477 // NB Need to keep the ObjectHeaders of deleted files
2478 // until the whole file has been deleted off
2479 tags.serialNumber++;
2483 newChunk = yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags,1);
2487 retVal = YAFFS_FAIL;
2492 // Ok, now fix up the Tnodes etc.
2494 if(tags.chunkId == 0)
2497 object->chunkId = newChunk;
2498 object->serial = tags.serialNumber;
2502 // It's a data chunk
2503 yaffs_PutChunkIntoFile(object, tags.chunkId, newChunk,0);
2508 yaffs_DeleteChunk(dev,oldChunk,markNAND,__LINE__);
2513 yaffs_ReleaseTempBuffer(dev,buffer,__LINE__);
2516 // Do any required cleanups
2517 for(i = 0; i < cleanups; i++)
2519 // Time to delete the file too
2520 object = yaffs_FindObjectByNumber(dev,dev->gcCleanupList[i]);
2523 yaffs_FreeTnode(dev,object->variant.fileVariant.top);
2524 object->variant.fileVariant.top = NULL;
2525 T(YAFFS_TRACE_GC,(TSTR("yaffs: About to finally delete object %d" TENDSTR),object->objectId));
2526 yaffs_DoGenericObjectDeletion(object);
2533 if(chunksBefore >= (chunksAfter = yaffs_GetErasedChunks(dev)))
2535 T(YAFFS_TRACE_GC,(TSTR("gc did not increase free chunks before %d after %d" TENDSTR),chunksBefore,chunksAfter));
2542 static yaffs_Object *yaffs_FindDeletedUnlinkedFile(yaffs_Device *dev)
2544 // find a file to delete
2545 struct list_head *i;
2549 //Scan the unlinked files looking for one to delete
2550 list_for_each(i,&dev->unlinkedDir->variant.directoryVariant.children)
2554 l = list_entry(i, yaffs_Object,siblings);
2565 static void yaffs_DoUnlinkedFileDeletion(yaffs_Device *dev)
2567 // This does background deletion on unlinked files.. only deleted ones.
2568 // If we don't have a file we're working on then find one
2569 if(!dev->unlinkedDeletion && dev->nDeletedFiles > 0)
2571 dev->unlinkedDeletion = yaffs_FindDeletedUnlinkedFile(dev);
2574 // OK, we're working on a file...
2575 if(dev->unlinkedDeletion)
2577 yaffs_Object *obj = dev->unlinkedDeletion;
2579 int limit; // Number of chunks to delete in a file.
2580 // NB this can be exceeded, but not by much.
2584 delresult = yaffs_DeleteWorker(obj, obj->variant.fileVariant.top, obj->variant.fileVariant.topLevel, 0,&limit);
2586 if(obj->nDataChunks == 0)
2588 // Done all the deleting of data chunks.
2589 // Now dump the header and clean up
2590 yaffs_FreeTnode(dev,obj->variant.fileVariant.top);
2591 obj->variant.fileVariant.top = NULL;
2592 yaffs_DoGenericObjectDeletion(obj);
2593 dev->nDeletedFiles--;
2594 dev->nUnlinkedFiles--;
2595 dev->nBackgroundDeletions++;
2596 dev->unlinkedDeletion = NULL;
2605 // New garbage collector
2606 // If we're very low on erased blocks then we do aggressive garbage collection
2607 // otherwise we do "leasurely" garbage collection.
2608 // Aggressive gc looks further (whole array) and will accept dirtier blocks.
2609 // Passive gc only inspects smaller areas and will only accept cleaner blocks.
2611 // The idea is to help clear out space in a more spread-out manner.
2612 // Dunno if it really does anything useful.
2614 int yaffs_CheckGarbageCollection(yaffs_Device *dev)
2618 int gcOk = YAFFS_OK;
2621 //yaffs_DoUnlinkedFileDeletion(dev);
2623 // This loop should pass the first time.
2624 // We'll only see looping here if the erase of the collected block fails.
2628 if(dev->nErasedBlocks <= (dev->nReservedBlocks + 2))
2630 // We need a block soon...
2635 // We're in no hurry
2639 block = yaffs_FindBlockForGarbageCollection(dev,aggressive);
2643 dev->garbageCollections++;
2646 dev->passiveGarbageCollections++;
2649 T(YAFFS_TRACE_GC,(TSTR("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),dev->nErasedBlocks,aggressive));
2651 gcOk = yaffs_GarbageCollectBlock(dev,block);
2654 if(dev->nErasedBlocks <= (dev->nReservedBlocks + 1))
2656 T(YAFFS_TRACE_GC,(TSTR("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d" TENDSTR),dev->nErasedBlocks,maxTries,block));
2658 } while((dev->nErasedBlocks <= (dev->nReservedBlocks + 1)) && (block > 0) && (maxTries < 5));
2660 return aggressive ? gcOk: YAFFS_OK;
2664 //////////////////////////// TAGS ///////////////////////////////////////
2670 void yaffs_CalcTagsECC(yaffs_Tags *tags)
2674 unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
2681 for(i = 0; i < 8; i++)
2683 for(j = 1; j &0xff; j<<=1)
2698 int yaffs_CheckECCOnTags(yaffs_Tags *tags)
2700 unsigned ecc = tags->ecc;
2702 yaffs_CalcTagsECC(tags);
2706 if(ecc && ecc <= 64)
2708 // TODO: Handle the failure better. Retire?
2709 unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
2713 b[ecc / 8] ^= (1 << (ecc & 7));
2715 // Now recvalc the ecc
2716 yaffs_CalcTagsECC(tags);
2718 return 1; // recovered error
2722 // Wierd ecc failure value
2723 // TODO Need to do somethiong here
2724 return -1; //unrecovered error
2730 static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr)
2732 yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr;
2734 yaffs_CalcTagsECC(tagsPtr);
2736 sparePtr->tagByte0 = tu->asBytes[0];
2737 sparePtr->tagByte1 = tu->asBytes[1];
2738 sparePtr->tagByte2 = tu->asBytes[2];
2739 sparePtr->tagByte3 = tu->asBytes[3];
2740 sparePtr->tagByte4 = tu->asBytes[4];
2741 sparePtr->tagByte5 = tu->asBytes[5];
2742 sparePtr->tagByte6 = tu->asBytes[6];
2743 sparePtr->tagByte7 = tu->asBytes[7];
2746 static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr)
2748 yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr;
2751 tu->asBytes[0]= sparePtr->tagByte0;
2752 tu->asBytes[1]= sparePtr->tagByte1;
2753 tu->asBytes[2]= sparePtr->tagByte2;
2754 tu->asBytes[3]= sparePtr->tagByte3;
2755 tu->asBytes[4]= sparePtr->tagByte4;
2756 tu->asBytes[5]= sparePtr->tagByte5;
2757 tu->asBytes[6]= sparePtr->tagByte6;
2758 tu->asBytes[7]= sparePtr->tagByte7;
2760 result = yaffs_CheckECCOnTags(tagsPtr);
2763 dev->tagsEccFixed++;
2767 dev->tagsEccUnfixed++;
2771 static void yaffs_SpareInitialise(yaffs_Spare *spare)
2773 memset(spare,0xFF,sizeof(yaffs_Spare));
2779 static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, const __u8 *buffer, yaffs_ExtendedTags *tags, int useReserve)
2781 // NB There must be tags, data is optional
2782 // If there is data, then an ECC is calculated on it.
2791 //yaffs_SpareInitialise(&spare);
2793 //if(!dev->useNANDECC && buffer)
2795 // yaffs_CalcECC(buffer,&spare);
2798 //yaffs_LoadTagsIntoSpare(&spare,tags);
2800 return yaffs_WriteNewChunkToNAND(dev,buffer,&spare,useReserve);
2805 static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId, int chunkInObject)
2807 return ( tags->chunkId == chunkInObject &&
2808 tags->objectId == objectId &&
2809 !tags->chunkDeleted) ? 1 : 0;
2813 /////////////////////////////////////////////////////////////////////////////////////////////////////////
2816 int yaffs_FindChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags *tags)
2818 //Get the Tnode, then get the level 0 offset chunk offset
2821 yaffs_ExtendedTags localTags;
2824 yaffs_Device *dev = in->myDev;
2829 // Passed a NULL, so use our own tags space
2833 tn = yaffs_FindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
2837 theChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits;
2839 retVal = yaffs_FindChunkInGroup(dev,theChunk,tags,in->objectId,chunkInInode);
2844 int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags *tags)
2846 //Get the Tnode, then get the level 0 offset chunk offset
2849 yaffs_ExtendedTags localTags;
2851 yaffs_Device *dev = in->myDev;
2856 // Passed a NULL, so use our own tags space
2860 tn = yaffs_FindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
2865 theChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits;
2867 retVal = yaffs_FindChunkInGroup(dev,theChunk,tags,in->objectId,chunkInInode);
2869 // Delete the entry in the filestructure (if found)
2872 tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] = 0;
2877 //T(("No level 0 found for %d\n", chunkInInode));
2882 //T(("Could not find %d to delete\n",chunkInInode));
2888 #ifdef YAFFS_PARANOID
2890 static int yaffs_CheckFileSanity(yaffs_Object *in)
2898 yaffs_Tags localTags;
2899 yaffs_Tags *tags = &localTags;
2904 if(in->variantType != YAFFS_OBJECT_TYPE_FILE)
2906 //T(("Object not a file\n"));
2910 objId = in->objectId;
2911 fSize = in->variant.fileVariant.fileSize;
2912 nChunks = (fSize + in->myDev->nBytesPerChunk -1)/in->myDev->nBytesPerChunk;
2914 for(chunk = 1; chunk <= nChunks; chunk++)
2916 tn = yaffs_FindLevel0Tnode(in->myDev,&in->variant.fileVariant, chunk);
2921 theChunk = tn->level0[chunk & YAFFS_TNODES_LEVEL0_MASK] << in->myDev->chunkGroupBits;
2923 if(yaffs_CheckChunkBits(dev,theChunk/dev->nChunksPerBlock,theChunk%dev->nChunksPerBlock))
2927 yaffs_ReadChunkTagsFromNAND(in->myDev,theChunk,tags,&chunkDeleted);
2928 if(yaffs_TagsMatch(tags,in->objectId,chunk,chunkDeleted))
2936 //T(("File problem file [%d,%d] NAND %d tags[%d,%d]\n",
2937 // objId,chunk,theChunk,tags->chunkId,tags->objectId);
2946 //T(("No level 0 found for %d\n", chunk));
2950 return failed ? YAFFS_FAIL : YAFFS_OK;
2955 static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan)
2957 // NB inScan is zero unless scanning. For forward scanning, inScan is > 0; for backward scanning inScan is < 0
2959 yaffs_Device *dev = in->myDev;
2961 yaffs_ExtendedTags existingTags;
2962 yaffs_ExtendedTags newTags;
2963 unsigned existingSerial, newSerial;
2965 if(in->variantType != YAFFS_OBJECT_TYPE_FILE)
2967 // Just ignore an attempt at putting a chunk into a non-file during scanning
2968 // If it is not during Scanning then something went wrong!
2971 T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy:attempt to put data chunk into a non-file" TENDSTR)));
2975 yaffs_DeleteChunk(dev,chunkInNAND,1,__LINE__);
2979 tn = yaffs_AddOrFindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
2985 existingChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK];
2989 // If we're scanning then we need to test for duplicates
2990 // NB This does not need to be efficient since it should only ever
2991 // happen when the power fails during a write, then only one
2992 // chunk should ever be affected.
2994 // Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
2995 // Update: For backward scanning we don't need to re-read tags so this is quite cheap.
2999 if(existingChunk != 0)
3001 // NB Right now existing chunk will not be real chunkId if the device >= 32MB
3002 // thus we have to do a FindChunkInFile to get the real chunk id.
3004 // We have a duplicate now we need to decide which one to use:
3006 // Backwards scanning YAFFS2: The old one is what we use, dump the new one.
3007 // Forward scanning YAFFS2: The new one is what we use, dump the old one.
3008 // YAFFS1: Get both sets of tags and compare serial numbers.
3014 // Only do this for forward scanning
3015 yaffs_ReadChunkWithTagsFromNAND(dev,chunkInNAND, NULL,&newTags);
3019 existingChunk = yaffs_FindChunkInFile(in,chunkInInode, &existingTags);
3022 if(existingChunk <=0)
3024 //Hoosterman - how did this happen?
3026 T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: existing chunk < 0 in scan" TENDSTR)));
3031 // NB The deleted flags should be false, otherwise the chunks will
3032 // not be loaded during a scan
3034 newSerial = newTags.serialNumber;
3035 existingSerial = existingTags.serialNumber;
3038 ( in->myDev->isYaffs2 ||
3039 existingChunk <= 0 ||
3040 ((existingSerial+1) & 3) == newSerial))
3042 // Forward scanning.
3044 // Delete the old one and drop through to update the tnode
3045 yaffs_DeleteChunk(dev,existingChunk,1,__LINE__);
3049 // Backward scanning or we want to use the existing one
3051 // Delete the new one and return early so that the tnode isn't changed
3052 yaffs_DeleteChunk(dev,chunkInNAND,1,__LINE__);
3059 if(existingChunk == 0)
3064 tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] = (chunkInNAND >> dev->chunkGroupBits);
3071 int yaffs_ReadChunkDataFromObject(yaffs_Object *in,int chunkInInode, __u8 *buffer)
3073 int chunkInNAND = yaffs_FindChunkInFile(in,chunkInInode,NULL);
3075 if(chunkInNAND >= 0)
3077 return yaffs_ReadChunkWithTagsFromNAND(in->myDev,chunkInNAND,buffer,NULL);
3081 T(YAFFS_TRACE_NANDACCESS,(TSTR("Chunk %d not found zero instead" TENDSTR),chunkInNAND));
3083 memset(buffer,0,in->myDev->nBytesPerChunk); // get sane data if you read a hole
3090 void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId,int markNAND,int lyn)
3094 yaffs_ExtendedTags tags;
3095 yaffs_BlockInfo *bi;
3097 if(chunkId <= 0) return;
3100 block = chunkId / dev->nChunksPerBlock;
3101 page = chunkId % dev->nChunksPerBlock;
3103 bi = yaffs_GetBlockInfo(dev,block);
3105 T(YAFFS_TRACE_DELETION,(TSTR("line %d delete of chunk %d" TENDSTR),lyn,chunkId));
3108 bi->blockState != YAFFS_BLOCK_STATE_COLLECTING &&
3111 // yaffs_SpareInitialise(&spare);
3113 #ifdef CONFIG_MTD_NAND_VERIFY_WRITE
3115 //read data before write, to ensure correct ecc
3116 //if we're using MTD verification under Linux
3117 yaffs_ReadChunkFromNAND(dev,chunkId,NULL,&spare,0);
3120 yaffs_InitialiseTags(&tags);
3122 tags.chunkDeleted = 1;
3125 yaffs_WriteChunkWithTagsToNAND(dev,chunkId,NULL,&tags);
3126 yaffs_HandleUpdateChunk(dev,chunkId,&tags);
3130 dev->nUnmarkedDeletions++;
3134 // Pull out of the management area.
3135 // If the whole block became dirty, this will kick off an erasure.
3136 if( bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING ||
3137 bi->blockState == YAFFS_BLOCK_STATE_FULL ||
3138 bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
3139 bi->blockState == YAFFS_BLOCK_STATE_COLLECTING)
3143 yaffs_ClearChunkBit(dev,block,page);
3146 if(bi->pagesInUse == 0 &&
3147 !bi->hasShrinkHeader &&
3148 bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING &&
3149 bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING)
3151 yaffs_BlockBecameDirty(dev,block);
3157 // T(("Bad news deleting chunk %d\n",chunkId));
3165 int yaffs_WriteChunkDataToObject(yaffs_Object *in,int chunkInInode, const __u8 *buffer,int nBytes,int useReserve)
3167 // Find old chunk Need to do this to get serial number
3168 // Write new one and patch into tree.
3169 // Invalidate old tags.
3172 yaffs_ExtendedTags prevTags;
3175 yaffs_ExtendedTags newTags;
3177 yaffs_Device *dev = in->myDev;
3179 yaffs_CheckGarbageCollection(dev);
3181 // Get the previous chunk at this location in the file if it exists
3182 prevChunkId = yaffs_FindChunkInFile(in,chunkInInode,&prevTags);
3185 yaffs_InitialiseTags(&newTags);
3187 newTags.chunkId = chunkInInode;
3188 newTags.objectId = in->objectId;
3189 newTags.serialNumber = (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1;
3190 newTags.byteCount = nBytes;
3192 // yaffs_CalcTagsECC(&newTags);
3194 newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,buffer,&newTags,useReserve);
3198 yaffs_PutChunkIntoFile(in,chunkInInode,newChunkId,0);
3201 if(prevChunkId >= 0)
3203 yaffs_DeleteChunk(dev,prevChunkId,1,__LINE__);
3207 yaffs_CheckFileSanity(in);
3218 // UpdateObjectHeader updates the header on NAND for an object.
3219 // If name is not NULL, then that new name is used.
3221 int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int isShrink)
3224 yaffs_BlockInfo *bi;
3226 yaffs_Device *dev = in->myDev;
3232 yaffs_ExtendedTags newTags;
3234 __u8 *buffer = NULL;
3235 YCHAR oldName[YAFFS_MAX_NAME_LENGTH+1];
3237 // __u8 bufferOld[YAFFS_BYTES_PER_CHUNK];
3239 yaffs_ObjectHeader *oh = NULL;
3240 // yaffs_ObjectHeader *ohOld = (yaffs_ObjectHeader *)bufferOld;
3243 if(!in->fake || force)
3246 yaffs_CheckGarbageCollection(dev);
3248 buffer = yaffs_GetTempBuffer(in->myDev,__LINE__);
3249 oh = (yaffs_ObjectHeader *)buffer;
3251 prevChunkId = in->chunkId;
3253 if(prevChunkId >= 0)
3255 yaffs_ReadChunkWithTagsFromNAND(dev,prevChunkId,buffer,NULL);
3256 memcpy(oldName,oh->name,sizeof(oh->name));
3259 memset(buffer,0xFF,dev->nBytesPerChunk);
3262 oh->type = in->variantType;
3264 oh->st_mode = in->st_mode;
3266 #ifdef CONFIG_YAFFS_WINCE
3267 oh->win_atime[0] = in->win_atime[0];
3268 oh->win_ctime[0] = in->win_ctime[0];
3269 oh->win_mtime[0] = in->win_mtime[0];
3270 oh->win_atime[1] = in->win_atime[1];
3271 oh->win_ctime[1] = in->win_ctime[1];
3272 oh->win_mtime[1] = in->win_mtime[1];
3274 oh->st_uid = in->st_uid;
3275 oh->st_gid = in->st_gid;
3276 oh->st_atime = in->st_atime;
3277 oh->st_mtime = in->st_mtime;
3278 oh->st_ctime = in->st_ctime;
3279 oh->st_rdev = in->st_rdev;
3283 oh->parentObjectId = in->parent->objectId;
3287 oh->parentObjectId = 0;
3290 //oh->sum = in->sum;
3293 memset(oh->name,0,sizeof(oh->name));
3294 yaffs_strncpy(oh->name,name,YAFFS_MAX_NAME_LENGTH);
3296 else if(prevChunkId)
3298 memcpy(oh->name, oldName,sizeof(oh->name));
3302 memset(oh->name,0,sizeof(oh->name));
3305 oh->isShrink = isShrink;
3307 switch(in->variantType)
3309 case YAFFS_OBJECT_TYPE_UNKNOWN:
3310 // Should not happen
3312 case YAFFS_OBJECT_TYPE_FILE:
3313 oh->fileSize = (oh->parentObjectId == YAFFS_OBJECTID_DELETED ||
3314 oh->parentObjectId == YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant.fileVariant.fileSize;
3316 case YAFFS_OBJECT_TYPE_HARDLINK:
3317 oh->equivalentObjectId = in->variant.hardLinkVariant.equivalentObjectId;
3319 case YAFFS_OBJECT_TYPE_SPECIAL:
3322 case YAFFS_OBJECT_TYPE_DIRECTORY:
3325 case YAFFS_OBJECT_TYPE_SYMLINK:
3326 yaffs_strncpy(oh->alias,in->variant.symLinkVariant.alias,YAFFS_MAX_ALIAS_LENGTH);
3327 oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
3332 yaffs_InitialiseTags(&newTags);
3334 newTags.chunkId = 0;
3335 newTags.objectId = in->objectId;
3336 newTags.serialNumber = in->serial;
3338 // Add extra info for file header
3340 newTags.extraHeaderInfoAvailable = 1;
3341 newTags.extraParentObjectId = oh->parentObjectId;
3342 newTags.extraFileLength = oh->fileSize;
3343 newTags.extraIsShrinkHeader = oh->isShrink;
3344 newTags.extraEquivalentObjectId = oh->equivalentObjectId;
3345 newTags.extraObjectType = in->variantType;
3347 // Create new chunk in NAND
3348 newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,buffer,&newTags, (prevChunkId >= 0) ? 1 : 0 );
3353 in->chunkId = newChunkId;
3355 if(prevChunkId >= 0)
3357 yaffs_DeleteChunk(dev,prevChunkId,1,__LINE__);
3362 // If this was a shrink, then mark the block that the chunk lives on
3365 bi = yaffs_GetBlockInfo(in->myDev,newChunkId / in->myDev->nChunksPerBlock);
3366 bi->hasShrinkHeader = 1;
3371 retVal = newChunkId;
3376 yaffs_ReleaseTempBuffer(dev,buffer,__LINE__);
3382 /////////////////////// Short Operations Cache ////////////////////////////////
3383 // In many siturations where there is no high level buffering (eg WinCE) a lot of
3384 // reads might be short sequential reads, and a lot of writes may be short
3385 // sequential writes. eg. scanning/writing a jpeg file.
3386 // In these cases, a short read/write cache can provide a huge perfomance benefit
3387 // with dumb-as-a-rock code.
3388 // There are a limited number (~10) of cache chunks per device so that we don't
3389 // need a very intelligent search.
3395 static void yaffs_FlushFilesChunkCache(yaffs_Object *obj)
3397 yaffs_Device *dev = obj->myDev;
3400 yaffs_ChunkCache *cache;
3401 int chunkWritten = 0;
3403 int nCaches = obj->myDev->nShortOpCaches;
3410 // Find the dirty cache for this object with the lowest chunk id.
3411 for(i = 0; i < nCaches; i++)
3413 if(dev->srCache[i].object == obj &&
3414 dev->srCache[i].dirty)
3416 if(!cache || dev->srCache[i].chunkId < lowest)
3418 cache = &dev->srCache[i];
3419 lowest = cache->chunkId;
3424 if(cache && !cache->locked)
3426 //Write it out and free it up
3429 nBytes = cache->object->variant.fileVariant.fileSize - ((cache->chunkId -1) * YAFFS_BYTES_PER_CHUNK);
3431 if(nBytes > YAFFS_BYTES_PER_CHUNK)
3433 nBytes= YAFFS_BYTES_PER_CHUNK;
3436 chunkWritten = yaffs_WriteChunkDataToObject(cache->object,
3442 cache->object = NULL;
3445 } while(cache && chunkWritten > 0);
3449 //Hoosterman, disk full while writing cache out.
3450 T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: no space during cache write" TENDSTR)));
3458 // Grab us a chunk for use.
3459 // First look for an empty one.
3460 // Then look for the least recently used non-dirty one.
3461 // Then look for the least recently used dirty one...., flush and look again.
3462 static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev)
3468 if(dev->nShortOpCaches > 0)
3470 for(i = 0; i < dev->nShortOpCaches; i++)
3472 if(!dev->srCache[i].object)
3474 //T(("Grabbing empty %d\n",i));
3476 //printf("Grabbing empty %d\n",i);
3478 return &dev->srCache[i];
3485 usage = 0; // just to stop the compiler grizzling
3487 for(i = 0; i < dev->nShortOpCaches; i++)
3489 if(!dev->srCache[i].dirty &&
3490 ((dev->srCache[i].lastUse < usage && theOne >= 0)||
3493 usage = dev->srCache[i].lastUse;
3498 //T(("Grabbing non-empty %d\n",theOne));
3500 //if(theOne >= 0) printf("Grabbed non-empty cache %d\n",theOne);
3502 return theOne >= 0 ? &dev->srCache[theOne] : NULL;
3512 static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev)
3514 yaffs_ChunkCache *cache;
3515 yaffs_Object *theObj;
3520 if(dev->nShortOpCaches > 0)
3522 // Try find a non-dirty one...
3524 cache = yaffs_GrabChunkCacheWorker(dev);
3528 // They were all dirty, find the last recently used object and flush
3529 // its cache, then find again.
3530 // NB what's here is not very accurate, we actually flush the object
3531 // the last recently used page.
3533 // With locking we can't assume we can use entry zero
3541 for(i = 0; i < dev->nShortOpCaches; i++)
3543 if( dev->srCache[i].object &&
3544 !dev->srCache[i].locked &&
3545 (dev->srCache[i].lastUse < usage || !cache))
3547 usage = dev->srCache[i].lastUse;
3548 theObj = dev->srCache[i].object;
3549 cache = &dev->srCache[i];
3554 if(!cache || cache->dirty)
3558 yaffs_FlushFilesChunkCache(theObj);
3561 cache = yaffs_GrabChunkCacheWorker(dev);
3565 //printf(" pushout %d\n",pushout);
3577 // Find a cached chunk
3578 static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object *obj, int chunkId)
3580 yaffs_Device *dev = obj->myDev;
3582 if(dev->nShortOpCaches > 0)
3584 for(i = 0; i < dev->nShortOpCaches; i++)
3586 if(dev->srCache[i].object == obj &&
3587 dev->srCache[i].chunkId == chunkId)
3591 return &dev->srCache[i];
3598 // Mark the chunk for the least recently used algorithym
3599 static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache, int isAWrite)
3602 if(dev->nShortOpCaches > 0)
3604 if( dev->srLastUse < 0 ||
3605 dev->srLastUse > 100000000)
3607 // Reset the cache usages
3609 for(i = 1; i < dev->nShortOpCaches; i++)
3611 dev->srCache[i].lastUse = 0;
3618 cache->lastUse = dev->srLastUse;
3627 // Invalidate a single cache page.
3628 // Do this when a whole page gets written,
3629 // ie the short cache for this page is no longer valid.
3630 static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId)
3632 if(object->myDev->nShortOpCaches > 0)
3634 yaffs_ChunkCache *cache = yaffs_FindChunkCache(object,chunkId);
3638 cache->object = NULL;
3644 // Invalidate all the cache pages associated with this object
3645 // Do this whenever ther file is deleted or resized.
3646 static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in)
3649 yaffs_Device *dev = in->myDev;
3651 if(dev->nShortOpCaches > 0)
3653 // Now invalidate it.
3654 for(i = 0; i < dev->nShortOpCaches; i++)
3656 if(dev->srCache[i].object == in)
3658 dev->srCache[i].object = NULL;
3668 ///////////////////////// File read/write ///////////////////////////////
3669 // Read and write have very similar structures.
3670 // In general the read/write has three parts to it
3671 // * An incomplete chunk to start with (if the read/write is not chunk-aligned)
3672 // * Some complete chunks
3673 // * An incomplete chunk to end off with
3675 // Curve-balls: the first chunk might also be the last chunk.
3677 int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 * buffer, __u32 offset, int nBytes)
3686 yaffs_ChunkCache *cache;
3694 chunk = offset / dev->nBytesPerChunk + 1; // The first chunk is 1
3695 start = offset % dev->nBytesPerChunk;
3697 // OK now check for the curveball where the start and end are in
3699 if( (start + n) < dev->nBytesPerChunk)
3705 nToCopy = dev->nBytesPerChunk - start;
3708 cache = yaffs_FindChunkCache(in,chunk);
3710 // If the chunk is already in the cache or it is less than a whole chunk
3711 // then use the cache (if there is caching)
3712 // else bypass the cache.
3713 if( cache || nToCopy != dev->nBytesPerChunk)
3715 if(dev->nShortOpCaches > 0)
3718 // If we can't find the data in the cache, then load it up.
3722 cache = yaffs_GrabChunkCache(in->myDev);
3724 cache->chunkId = chunk;
3727 yaffs_ReadChunkDataFromObject(in,chunk,cache->data);
3731 yaffs_UseChunkCache(dev,cache,0);
3735 #ifdef CONFIG_YAFFS_WINCE
3736 yfsd_UnlockYAFFS(TRUE);
3738 memcpy(buffer,&cache->data[start],nToCopy);
3740 #ifdef CONFIG_YAFFS_WINCE
3741 yfsd_LockYAFFS(TRUE);
3747 // Read into the local buffer then copy...
3749 __u8 *localBuffer = yaffs_GetTempBuffer(dev,__LINE__);
3750 yaffs_ReadChunkDataFromObject(in,chunk,localBuffer);
3751 #ifdef CONFIG_YAFFS_WINCE
3752 yfsd_UnlockYAFFS(TRUE);
3754 memcpy(buffer,&localBuffer[start],nToCopy);
3756 #ifdef CONFIG_YAFFS_WINCE
3757 yfsd_LockYAFFS(TRUE);
3759 yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
3765 #ifdef CONFIG_YAFFS_WINCE
3766 __u8 *localBuffer = yaffs_GetTempBuffer(dev,__LINE__);
3768 // Under WinCE can't do direct transfer. Need to use a local buffer.
3769 // This is because we otherwise screw up WinCE's memory mapper
3770 yaffs_ReadChunkDataFromObject(in,chunk,localBuffer);
3772 #ifdef CONFIG_YAFFS_WINCE
3773 yfsd_UnlockYAFFS(TRUE);
3775 memcpy(buffer,localBuffer,dev->nBytesPerChunk);
3777 #ifdef CONFIG_YAFFS_WINCE
3778 yfsd_LockYAFFS(TRUE);
3779 yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
3783 // A full chunk. Read directly into the supplied buffer.
3784 yaffs_ReadChunkDataFromObject(in,chunk,buffer);
3800 int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, int nBytes, int writeThrough)
3809 int startOfWrite = offset;
3810 int chunkWritten = 0;
3818 while(n > 0 && chunkWritten >= 0)
3820 chunk = offset / dev->nBytesPerChunk + 1;
3821 start = offset % dev->nBytesPerChunk;
3824 // OK now check for the curveball where the start and end are in
3827 if((start + n) < dev->nBytesPerChunk)
3831 // Now folks, to calculate how many bytes to write back....
3832 // If we're overwriting and not writing to then end of file then
3833 // we need to write back as much as was there before.
3835 nBytesRead = in->variant.fileVariant.fileSize - ((chunk -1) * dev->nBytesPerChunk);
3837 if(nBytesRead > dev->nBytesPerChunk)
3839 nBytesRead = dev->nBytesPerChunk;
3842 nToWriteBack = (nBytesRead > (start + n)) ? nBytesRead : (start +n);
3847 nToCopy = dev->nBytesPerChunk - start;
3848 nToWriteBack = dev->nBytesPerChunk;
3851 if(nToCopy != dev->nBytesPerChunk)
3853 // An incomplete start or end chunk (or maybe both start and end chunk)
3854 if(dev->nShortOpCaches > 0)
3856 yaffs_ChunkCache *cache;
3857 // If we can't find the data in the cache, then load it up.
3858 cache = yaffs_FindChunkCache(in,chunk);
3859 if(!cache && yaffs_CheckSpaceForChunkCache(in->myDev))
3861 cache = yaffs_GrabChunkCache(in->myDev);
3863 cache->chunkId = chunk;
3866 yaffs_ReadChunkDataFromObject(in,chunk,cache->data);
3871 yaffs_UseChunkCache(dev,cache,1);
3873 #ifdef CONFIG_YAFFS_WINCE
3874 yfsd_UnlockYAFFS(TRUE);
3877 memcpy(&cache->data[start],buffer,nToCopy);
3879 #ifdef CONFIG_YAFFS_WINCE
3880 yfsd_LockYAFFS(TRUE);
3883 cache->nBytes = nToWriteBack;
3887 chunkWritten = yaffs_WriteChunkDataToObject(cache->object,
3897 chunkWritten = -1; // fail the write
3902 // An incomplete start or end chunk (or maybe both start and end chunk)
3903 // Read into the local buffer then copy, then copy over and write back.
3905 __u8 *localBuffer = yaffs_GetTempBuffer(dev,__LINE__);
3907 yaffs_ReadChunkDataFromObject(in,chunk,localBuffer);
3909 #ifdef CONFIG_YAFFS_WINCE
3910 yfsd_UnlockYAFFS(TRUE);
3913 memcpy(&localBuffer[start],buffer,nToCopy);
3915 #ifdef CONFIG_YAFFS_WINCE
3916 yfsd_LockYAFFS(TRUE);
3918 chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,localBuffer,nToWriteBack,0);
3920 yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
3922 //T(("Write with readback to chunk %d %d start %d copied %d wrote back %d\n",chunk,chunkWritten,start, nToCopy, nToWriteBack));
3929 #ifdef CONFIG_YAFFS_WINCE
3930 // Under WinCE can't do direct transfer. Need to use a local buffer.
3931 // This is because we otherwise screw up WinCE's memory mapper
3932 __u8 *localBuffer = yaffs_GetTempBuffer(dev,__LINE__);
3933 #ifdef CONFIG_YAFFS_WINCE
3934 yfsd_UnlockYAFFS(TRUE);
3936 memcpy(localBuffer,buffer,dev->nBytesPerChunk);
3937 #ifdef CONFIG_YAFFS_WINCE
3938 yfsd_LockYAFFS(TRUE);
3940 chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,localBuffer,dev->nBytesPerChunk,0);
3941 yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
3943 // A full chunk. Write directly from the supplied buffer.
3944 chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,buffer,dev->nBytesPerChunk,0);
3946 // Since we've overwritten the cached data, we better invalidate it.
3947 yaffs_InvalidateChunkCache(in,chunk);
3948 //T(("Write to chunk %d %d\n",chunk,chunkWritten));
3951 if(chunkWritten >= 0)
3961 // Update file object
3963 if((startOfWrite + nDone) > in->variant.fileVariant.fileSize)
3965 in->variant.fileVariant.fileSize = (startOfWrite + nDone);
3973 static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize)
3976 yaffs_Device *dev = in->myDev;
3977 int oldFileSize = in->variant.fileVariant.fileSize;
3980 int lastDel = 1 + (oldFileSize-1)/dev->nBytesPerChunk;
3982 int startDel = 1 + (newSize + dev->nBytesPerChunk - 1)/
3983 dev->nBytesPerChunk;
3987 // Delete backwards so that we don't end up with holes if
3988 // power is lost part-way through the operation.
3989 for(i = lastDel; i >= startDel; i--)
3991 // NB this could be optimised somewhat,
3992 // eg. could retrieve the tags and write them without
3993 // using yaffs_DeleteChunk
3995 chunkId = yaffs_FindAndDeleteChunkInFile(in,i,NULL);
3998 if(chunkId < (dev->internalStartBlock * dev->nChunksPerBlock) ||
3999 chunkId >= ((dev->internalEndBlock+1) * dev->nChunksPerBlock))
4001 T(YAFFS_TRACE_ALWAYS,(TSTR("Found daft chunkId %d for %d"TENDSTR),chunkId,i));
4006 yaffs_DeleteChunk(dev,chunkId,1,__LINE__);
4013 int yaffs_ResizeFile(yaffs_Object *in, int newSize)
4016 int oldFileSize = in->variant.fileVariant.fileSize;
4017 int sizeOfPartialChunk;
4018 yaffs_Device *dev = in->myDev;
4020 sizeOfPartialChunk = newSize % dev->nBytesPerChunk;
4023 yaffs_FlushFilesChunkCache(in);
4024 yaffs_InvalidateWholeChunkCache(in);
4026 yaffs_CheckGarbageCollection(dev);
4028 if(in->variantType != YAFFS_OBJECT_TYPE_FILE)
4030 return yaffs_GetFileSize(in);
4033 if(newSize < oldFileSize)
4036 yaffs_PruneResizedChunks(in,newSize);
4038 if(sizeOfPartialChunk != 0)
4040 int lastChunk = 1+ newSize/dev->nBytesPerChunk;
4041 __u8 *localBuffer = yaffs_GetTempBuffer(dev,__LINE__);
4043 // Got to read and rewrite the last chunk with its new size and zero pad
4044 yaffs_ReadChunkDataFromObject(in,lastChunk,localBuffer);
4046 memset(localBuffer + sizeOfPartialChunk,0, dev->nBytesPerChunk - sizeOfPartialChunk);
4048 yaffs_WriteChunkDataToObject(in,lastChunk,localBuffer,sizeOfPartialChunk,1);
4050 yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
4053 in->variant.fileVariant.fileSize = newSize;
4055 yaffs_PruneFileStructure(dev,&in->variant.fileVariant);
4057 // Write a new object header to show we've shrunk the file
4058 // Do this only if the file is not in the deleted directories.
4059 if(in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
4060 in->parent->objectId != YAFFS_OBJECTID_DELETED
4063 yaffs_UpdateObjectHeader(in,NULL, 0, 1);
4077 loff_t yaffs_GetFileSize(yaffs_Object *obj)
4079 obj = yaffs_GetEquivalentObject(obj);
4081 switch(obj->variantType)
4083 case YAFFS_OBJECT_TYPE_FILE:
4084 return obj->variant.fileVariant.fileSize;
4085 case YAFFS_OBJECT_TYPE_SYMLINK:
4086 return yaffs_strlen(obj->variant.symLinkVariant.alias);
4094 // yaffs_FlushFile() updates the file's
4097 int yaffs_FlushFile(yaffs_Object *in, int updateTime)
4102 //T(("flushing object header\n"));
4104 yaffs_FlushFilesChunkCache(in);
4107 #ifdef CONFIG_YAFFS_WINCE
4108 yfsd_WinFileTimeNow(in->win_mtime);
4111 in->st_mtime = Y_CURRENT_TIME;
4116 retVal = (yaffs_UpdateObjectHeader(in,NULL,0,0) >= 0)? YAFFS_OK : YAFFS_FAIL;
4128 static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
4131 // First off, invalidate the file's data in the cache, without flushing.
4132 yaffs_InvalidateWholeChunkCache(in);
4134 if(in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir))
4136 // Move to the unlinked directory so we have a record that it was deleted.
4137 yaffs_ChangeObjectName(in, in->myDev->deletedDir,NULL,0);
4142 yaffs_RemoveObjectFromDirectory(in);
4143 yaffs_DeleteChunk(in->myDev,in->chunkId,1,__LINE__);
4149 in->myInode->u.generic_ip = NULL;
4155 yaffs_FreeObject(in);
4160 // yaffs_DeleteFile deletes the whole file data
4161 // and the inode associated with the file.
4162 // It does not delete the links associated with the file.
4163 static int yaffs_UnlinkFile(yaffs_Object *in)
4166 #ifdef CONFIG_YAFFS_DISABLE_BACKGROUND_DELETION
4168 // Delete the file data & tnodes
4170 yaffs_DeleteWorker(in, in->variant.fileVariant.top, in->variant.fileVariant.topLevel, 0,NULL);
4173 yaffs_FreeTnode(in->myDev,in->variant.fileVariant.top);
4175 return yaffs_DoGenericObjectDeletion(in);
4178 int immediateDeletion=0;
4183 //in->myDev->nUnlinkedFiles++;
4184 //in->renameAllowed = 0;
4188 immediateDeletion = 1;
4194 immediateDeletion = 1;
4198 if(immediateDeletion)
4200 retVal = yaffs_ChangeObjectName(in, in->myDev->deletedDir,NULL,0);
4201 T(YAFFS_TRACE_TRACING,(TSTR("yaffs: immediate deletion of file %d" TENDSTR),in->objectId));
4203 in->myDev->nDeletedFiles++;
4204 if( 0 && in->myDev->isYaffs2)
4206 yaffs_ResizeFile(in,0);
4208 yaffs_SoftDeleteFile(in);
4212 retVal = yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,NULL,0);
4222 int yaffs_DeleteFile(yaffs_Object *in)
4224 int retVal = YAFFS_OK;
4226 if(in->nDataChunks > 0)
4228 // Use soft deletion
4231 retVal = yaffs_UnlinkFile(in);
4233 if(retVal == YAFFS_OK &&
4238 in->myDev->nDeletedFiles++;
4239 yaffs_SoftDeleteFile(in);
4241 return in->deleted ? YAFFS_OK : YAFFS_FAIL;
4245 // The file has no data chunks so we toss it immediately
4246 yaffs_FreeTnode(in->myDev,in->variant.fileVariant.top);
4247 in->variant.fileVariant.top = NULL;
4248 yaffs_DoGenericObjectDeletion(in);
4254 static int yaffs_DeleteDirectory(yaffs_Object *in)
4256 //First check that the directory is empty.
4257 if(list_empty(&in->variant.directoryVariant.children))
4259 return yaffs_DoGenericObjectDeletion(in);
4266 static int yaffs_DeleteSymLink(yaffs_Object *in)
4268 YFREE(in->variant.symLinkVariant.alias);
4270 return yaffs_DoGenericObjectDeletion(in);
4273 static int yaffs_DeleteHardLink(yaffs_Object *in)
4275 // remove this hardlink from the list assocaited with the equivalent
4277 list_del(&in->hardLinks);
4278 return yaffs_DoGenericObjectDeletion(in);
4282 static void yaffs_DestroyObject(yaffs_Object *obj)
4284 switch(obj->variantType)
4286 case YAFFS_OBJECT_TYPE_FILE: yaffs_DeleteFile(obj); break;
4287 case YAFFS_OBJECT_TYPE_DIRECTORY: yaffs_DeleteDirectory(obj); break;
4288 case YAFFS_OBJECT_TYPE_SYMLINK: yaffs_DeleteSymLink(obj); break;
4289 case YAFFS_OBJECT_TYPE_HARDLINK: yaffs_DeleteHardLink(obj); break;
4290 case YAFFS_OBJECT_TYPE_SPECIAL: yaffs_DoGenericObjectDeletion(obj); break;
4291 case YAFFS_OBJECT_TYPE_UNKNOWN: break; // should not happen.
4296 static int yaffs_UnlinkWorker(yaffs_Object *obj)
4300 if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
4302 return yaffs_DeleteHardLink(obj);
4304 else if(!list_empty(&obj->hardLinks))
4306 // Curve ball: We're unlinking an object that has a hardlink.
4308 // This problem arises because we are not strictly following
4309 // The Linux link/inode model.
4311 // We can't really delete the object.
4312 // Instead, we do the following:
4313 // - Select a hardlink.
4314 // - Unhook it from the hard links
4315 // - Unhook it from its parent directory (so that the rename can work)
4316 // - Rename the object to the hardlink's name.
4317 // - Delete the hardlink
4322 YCHAR name[YAFFS_MAX_NAME_LENGTH+1];
4324 hl = list_entry(obj->hardLinks.next,yaffs_Object,hardLinks);
4326 list_del_init(&hl->hardLinks);
4327 list_del_init(&hl->siblings);
4329 yaffs_GetObjectName(hl,name,YAFFS_MAX_NAME_LENGTH+1);
4331 retVal = yaffs_ChangeObjectName(obj, hl->parent, name,0);
4333 if(retVal == YAFFS_OK)
4335 retVal = yaffs_DoGenericObjectDeletion(hl);
4342 switch(obj->variantType)
4344 case YAFFS_OBJECT_TYPE_FILE:
4345 return yaffs_UnlinkFile(obj);
4347 case YAFFS_OBJECT_TYPE_DIRECTORY:
4348 return yaffs_DeleteDirectory(obj);
4350 case YAFFS_OBJECT_TYPE_SYMLINK:
4351 return yaffs_DeleteSymLink(obj);
4353 case YAFFS_OBJECT_TYPE_SPECIAL:
4354 return yaffs_DoGenericObjectDeletion(obj);
4356 case YAFFS_OBJECT_TYPE_HARDLINK:
4357 case YAFFS_OBJECT_TYPE_UNKNOWN:
4364 int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name)
4368 obj = yaffs_FindObjectByName(dir,name);
4370 if(obj && obj->unlinkAllowed)
4372 return yaffs_UnlinkWorker(obj);
4379 //////////////// Initialisation Scanning /////////////////
4383 // For now we use the SmartMedia check.
4384 // We look at the blockStatus byte in the first two chunks
4385 // These must be 0xFF to pass as OK.
4386 // todo: this function needs to be modifyable foir different NAND types
4387 // and different chunk sizes. Suggest make this into a per-device configurable
4389 static int yaffs_IsBlockBad(yaffs_Device *dev, int blk)
4391 yaffsExtendedTags *tags;
4393 yaffs_ReadChunkFromNAND(dev,blk * dev->nChunksPerBlock,NULL,&tags,1);
4395 if(yaffs_CountBits(spare.blockStatus) < 7)
4400 if(spare.blockStatus != 0xFF)
4405 yaffs_ReadChunkFromNAND(dev,blk * dev->nChunksPerBlock + 1,NULL,&spare,1);
4408 if(yaffs_CountBits(spare.blockStatus) < 7)
4413 if(spare.blockStatus != 0xFF)
4434 static int yaffs_Scan(yaffs_Device *dev)
4436 yaffs_ExtendedTags tags;
4441 int nBlocksToScan = 0;
4446 yaffs_BlockState state;
4447 yaffs_Object *hardList = NULL;
4449 yaffs_BlockInfo *bi;
4451 yaffs_ObjectHeader *oh;
4453 yaffs_Object *parent;
4454 int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
4458 yaffs_BlockIndex *blockIndex = NULL;
4460 T(YAFFS_TRACE_SCAN,(TSTR("yaffs_Scan starts intstartblk %d intendblk %d..." TENDSTR),dev->internalStartBlock,dev->internalEndBlock));
4462 chunkData = yaffs_GetTempBuffer(dev,__LINE__);
4465 dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
4469 blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
4473 // Scan all the blocks to determine their state
4474 for(blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++)
4476 bi = yaffs_GetBlockInfo(dev,blk);
4477 yaffs_ClearChunkBits(dev,blk);
4479 bi->softDeletions = 0;
4481 yaffs_QueryInitialBlockState(dev,blk,&state,&sequenceNumber);
4483 bi->blockState = state;
4484 bi->sequenceNumber = sequenceNumber;
4486 T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("Block scanning block %d state %d seq %d" TENDSTR),blk,state,sequenceNumber));
4488 if(state == YAFFS_BLOCK_STATE_DEAD)
4490 T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("block %d is bad" TENDSTR),blk));
4492 else if(state == YAFFS_BLOCK_STATE_EMPTY)
4494 T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("Block empty " TENDSTR)));
4495 dev->nErasedBlocks++;
4496 dev->nFreeChunks += dev->nChunksPerBlock;
4498 else if(state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
4501 // Determine the highest sequence number
4502 if( dev->isYaffs2 &&
4503 sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
4504 sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER)
4507 blockIndex[nBlocksToScan].seq = sequenceNumber;
4508 blockIndex[nBlocksToScan].block = blk;
4512 if(sequenceNumber >= dev->sequenceNumber)
4514 dev->sequenceNumber = sequenceNumber;
4517 else if(dev->isYaffs2)
4519 // TODO: Nasty sequence number!
4520 T(YAFFS_TRACE_SCAN,(TSTR("Block scanning block %d has bad sequence number %d" TENDSTR),blk,sequenceNumber));
4527 // Dungy old bubble sort for now...
4530 yaffs_BlockIndex temp;
4534 for(i = 0; i < nBlocksToScan; i++)
4535 for(j = i+1; j < nBlocksToScan; j++)
4536 if(blockIndex[i].seq > blockIndex[j].seq)
4538 temp = blockIndex[j];
4539 blockIndex[j] = blockIndex[i];
4540 blockIndex[i] = temp;
4545 // Now scan the blocks looking at the data.
4549 endIterator = nBlocksToScan-1;
4550 T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("%d blocks to be scanned" TENDSTR),nBlocksToScan));
4554 startIterator = dev->internalStartBlock;
4555 endIterator = dev->internalEndBlock;
4558 // For each block....
4559 for(blockIterator = startIterator; blockIterator <= endIterator; blockIterator++)
4564 // get the block to scan in the correct order
4565 blk = blockIndex[blockIterator].block;
4569 blk = blockIterator;
4573 bi = yaffs_GetBlockInfo(dev,blk);
4574 state = bi->blockState;
4578 // For each chunk in each block that needs scanning....
4579 for(c = 0; c < dev->nChunksPerBlock &&
4580 state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++)
4582 // Read the tags and decide what to do
4583 chunk = blk * dev->nChunksPerBlock + c;
4585 yaffs_ReadChunkWithTagsFromNAND(dev,chunk,NULL,&tags);
4587 // Let's have a good look at this chunk...
4590 if(!dev->isYaffs2 && tags.chunkDeleted)
4595 dev->nFreeChunks ++;
4596 //T((" %d %d deleted\n",blk,c));
4598 else if(!tags.chunkUsed)
4600 // An unassigned chunk in the block
4601 // This means that either the block is empty or
4602 // this is the one being allocated from
4606 // We're looking at the first chunk in the block so the block is unused
4607 state = YAFFS_BLOCK_STATE_EMPTY;
4608 dev->nErasedBlocks++;
4612 // this is the block being allocated from
4613 T(YAFFS_TRACE_SCAN,(TSTR(" Allocating from %d %d" TENDSTR),blk,c));
4614 state = YAFFS_BLOCK_STATE_ALLOCATING;
4615 dev->allocationBlock = blk;
4616 dev->allocationPage = c;
4617 dev->allocationBlockFinder = blk; // Set it to here to encourage the allocator to
4618 // go forth from here.
4619 //Yaffs2 sanity check:
4620 // This should be the one with the highest sequence number
4621 if(dev->isYaffs2 && (dev->sequenceNumber != bi->sequenceNumber))
4623 T(YAFFS_TRACE_ALWAYS,
4624 (TSTR("yaffs: Allocation block %d was not highest sequence id: block seq = %d, dev seq = %d" TENDSTR),
4625 blk,bi->sequenceNumber,dev->sequenceNumber));
4629 dev->nFreeChunks += (dev->nChunksPerBlock - c);
4631 else if(tags.chunkId > 0)
4633 // chunkId > 0 so it is a data chunk...
4634 unsigned int endpos;
4636 yaffs_SetChunkBit(dev,blk,c);
4639 in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,YAFFS_OBJECT_TYPE_FILE);
4640 // PutChunkIntoFile checks for a clash (two data chunks with
4641 // the same chunkId).
4642 yaffs_PutChunkIntoFile(in,tags.chunkId,chunk,1);
4643 endpos = (tags.chunkId - 1)* dev->nBytesPerChunk + tags.byteCount;
4644 if(in->variantType == YAFFS_OBJECT_TYPE_FILE && in->variant.fileVariant.scannedFileSize <endpos)
4646 in->variant.fileVariant.scannedFileSize = endpos;
4647 if(!dev->useHeaderFileSize)
4649 in->variant.fileVariant.fileSize = in->variant.fileVariant.scannedFileSize;
4653 //T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId));
4657 // chunkId == 0, so it is an ObjectHeader.
4658 // Thus, we read in the object header and make the object
4659 yaffs_SetChunkBit(dev,blk,c);
4662 yaffs_ReadChunkWithTagsFromNAND(dev,chunk,chunkData,NULL);
4664 oh = (yaffs_ObjectHeader *)chunkData;
4666 in = yaffs_FindObjectByNumber(dev,tags.objectId);
4667 if(in && in->variantType != oh->type)
4669 // This should not happen, but somehow
4670 // Wev'e ended up with an objectId that has been reused but not yet
4671 // deleted, and worse still it has changed type. Delete the old object.
4673 yaffs_DestroyObject(in);
4678 in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,oh->type);
4682 // We have already filled this one. We have a duplicate and need to resolve it.
4684 unsigned existingSerial = in->serial;
4685 unsigned newSerial = tags.serialNumber;
4687 if( dev->isYaffs2 ||
4688 ((existingSerial+1) & 3) == newSerial)
4690 // Use new one - destroy the exisiting one
4691 yaffs_DeleteChunk(dev,in->chunkId,1,__LINE__);
4696 // Use existing - destroy this one.
4697 yaffs_DeleteChunk(dev,chunk,1,__LINE__);
4702 (tags.objectId == YAFFS_OBJECTID_ROOT ||
4703 tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))
4705 // We only load some info, don't fiddle with directory structure
4707 in->variantType = oh->type;
4709 in->st_mode = oh->st_mode;
4710 #ifdef CONFIG_YAFFS_WINCE
4711 in->win_atime[0] = oh->win_atime[0];
4712 in->win_ctime[0] = oh->win_ctime[0];
4713 in->win_mtime[0] = oh->win_mtime[0];
4714 in->win_atime[1] = oh->win_atime[1];
4715 in->win_ctime[1] = oh->win_ctime[1];
4716 in->win_mtime[1] = oh->win_mtime[1];
4718 in->st_uid = oh->st_uid;
4719 in->st_gid = oh->st_gid;
4720 in->st_atime = oh->st_atime;
4721 in->st_mtime = oh->st_mtime;
4722 in->st_ctime = oh->st_ctime;
4723 in->st_rdev = oh->st_rdev;
4725 in->chunkId = chunk;
4730 // we need to load this info
4733 in->variantType = oh->type;
4735 in->st_mode = oh->st_mode;
4736 #ifdef CONFIG_YAFFS_WINCE
4737 in->win_atime[0] = oh->win_atime[0];
4738 in->win_ctime[0] = oh->win_ctime[0];
4739 in->win_mtime[0] = oh->win_mtime[0];
4740 in->win_atime[1] = oh->win_atime[1];
4741 in->win_ctime[1] = oh->win_ctime[1];
4742 in->win_mtime[1] = oh->win_mtime[1];
4744 in->st_uid = oh->st_uid;
4745 in->st_gid = oh->st_gid;
4746 in->st_atime = oh->st_atime;
4747 in->st_mtime = oh->st_mtime;
4748 in->st_ctime = oh->st_ctime;
4749 in->st_rdev = oh->st_rdev;
4751 in->chunkId = chunk;
4753 yaffs_SetObjectName(in,oh->name);
4756 // directory stuff...
4757 // hook up to parent
4759 parent = yaffs_FindOrCreateObjectByNumber(dev,oh->parentObjectId,YAFFS_OBJECT_TYPE_DIRECTORY);
4760 if(parent->variantType == YAFFS_OBJECT_TYPE_UNKNOWN)
4762 // Set up as a directory
4763 parent->variantType = YAFFS_OBJECT_TYPE_DIRECTORY;
4764 INIT_LIST_HEAD(&parent->variant.directoryVariant.children);
4766 else if(parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
4768 // Hoosterman, another problem....
4769 // We're trying to use a non-directory as a directory
4771 T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." TENDSTR)));
4772 parent = dev->lostNFoundDir;
4775 yaffs_AddObjectToDirectory(parent,in);
4777 if(0 && (parent == dev->deletedDir ||
4778 parent == dev->unlinkedDir))
4780 in->deleted = 1; // If it is unlinked at start up then it wants deleting
4781 dev->nDeletedFiles++;
4784 // Note re hardlinks.
4785 // Since we might scan a hardlink before its equivalent object is scanned
4786 // we put them all in a list.
4787 // After scanning is complete, we should have all the objects, so we run through this
4788 // list and fix up all the chains.
4790 switch(in->variantType)
4792 case YAFFS_OBJECT_TYPE_UNKNOWN: // Todo got a problem
4794 case YAFFS_OBJECT_TYPE_FILE:
4795 if(dev->isYaffs2 && oh->isShrink)
4797 // Prune back the shrunken chunks
4798 yaffs_PruneResizedChunks(in,oh->fileSize);
4799 // Mark the block as having a shrinkHeader
4800 bi->hasShrinkHeader = 1;
4803 if(dev->useHeaderFileSize)
4805 in->variant.fileVariant.fileSize = oh->fileSize;
4808 case YAFFS_OBJECT_TYPE_HARDLINK:
4809 in->variant.hardLinkVariant.equivalentObjectId = oh->equivalentObjectId;
4810 in->hardLinks.next = (struct list_head *)hardList;
4813 case YAFFS_OBJECT_TYPE_DIRECTORY: // Do nothing
4815 case YAFFS_OBJECT_TYPE_SPECIAL: // Do nothing
4817 case YAFFS_OBJECT_TYPE_SYMLINK: // Do nothing
4818 in->variant.symLinkVariant.alias = yaffs_CloneString(oh->alias);
4822 if(parent == dev->deletedDir)
4824 yaffs_DestroyObject(in);
4825 bi->hasShrinkHeader = 1;
4827 //T((" %d %d header %d \"%s\" type %d\n",blk,c,tags.objectId,oh->name,in->variantType));
4832 if(state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
4834 // If we got this far while scanning, then the block is fully allocated.
4835 state = YAFFS_BLOCK_STATE_FULL;
4838 bi->blockState = state;
4840 // Now let's see if it was dirty
4841 if( bi->pagesInUse == 0 &&
4842 !bi->hasShrinkHeader &&
4843 bi->blockState == YAFFS_BLOCK_STATE_FULL)
4845 yaffs_BlockBecameDirty(dev,blk);
4855 // Ok, we've done all the scanning.
4857 // Fix up the hard link chains.
4858 // We should now have scanned all the objects, now it's time to add these
4863 hardList = (yaffs_Object *)(hardList->hardLinks.next);
4865 in = yaffs_FindObjectByNumber(dev,hl->variant.hardLinkVariant.equivalentObjectId);
4869 // Add the hardlink pointers
4870 hl->variant.hardLinkVariant.equivalentObject=in;
4871 list_add(&hl->hardLinks,&in->hardLinks);
4875 //Todo Need to report/handle this better.
4876 // Got a problem... hardlink to a non-existant object
4877 hl->variant.hardLinkVariant.equivalentObject=NULL;
4878 INIT_LIST_HEAD(&hl->hardLinks);
4885 struct list_head *i;
4886 struct list_head *n;
4889 // Soft delete all the unlinked files
4890 list_for_each_safe(i,n,&dev->unlinkedDir->variant.directoryVariant.children)
4894 l = list_entry(i, yaffs_Object,siblings);
4895 yaffs_DestroyObject(l);
4900 yaffs_ReleaseTempBuffer(dev,chunkData,__LINE__);
4902 T(YAFFS_TRACE_SCAN,(TSTR("yaffs_Scan ends" TENDSTR)));
4908 static int yaffs_ScanBackwards(yaffs_Device *dev)
4910 yaffs_ExtendedTags tags;
4915 int nBlocksToScan = 0;
4920 yaffs_BlockState state;
4921 yaffs_Object *hardList = NULL;
4923 yaffs_BlockInfo *bi;
4925 yaffs_ObjectHeader *oh;
4927 yaffs_Object *parent;
4928 int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
4932 yaffs_BlockIndex *blockIndex = NULL;
4937 T(YAFFS_TRACE_SCAN,(TSTR("yaffs_ScanBackwards is only for YAFFS2!" TENDSTR)));
4941 T(YAFFS_TRACE_SCAN,(TSTR("yaffs_ScanBackwards starts intstartblk %d intendblk %d..." TENDSTR),dev->internalStartBlock,dev->internalEndBlock));
4943 chunkData = yaffs_GetTempBuffer(dev,__LINE__);
4946 dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
4950 blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
4954 // Scan all the blocks to determine their state
4955 for(blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++)
4957 bi = yaffs_GetBlockInfo(dev,blk);
4958 yaffs_ClearChunkBits(dev,blk);
4960 bi->softDeletions = 0;
4962 yaffs_QueryInitialBlockState(dev,blk,&state,&sequenceNumber);
4964 bi->blockState = state;
4965 bi->sequenceNumber = sequenceNumber;
4967 T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("Block scanning block %d state %d seq %d" TENDSTR),blk,state,sequenceNumber));
4969 if(state == YAFFS_BLOCK_STATE_DEAD)
4971 T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("block %d is bad" TENDSTR),blk));
4973 else if(state == YAFFS_BLOCK_STATE_EMPTY)
4975 T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("Block empty " TENDSTR)));
4976 dev->nErasedBlocks++;
4977 dev->nFreeChunks += dev->nChunksPerBlock;
4979 else if(state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
4982 // Determine the highest sequence number
4983 if( dev->isYaffs2 &&
4984 sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
4985 sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER)
4988 blockIndex[nBlocksToScan].seq = sequenceNumber;
4989 blockIndex[nBlocksToScan].block = blk;
4993 if(sequenceNumber >= dev->sequenceNumber)
4995 dev->sequenceNumber = sequenceNumber;
4998 else if(dev->isYaffs2)
5000 // TODO: Nasty sequence number!
5001 T(YAFFS_TRACE_SCAN,(TSTR("Block scanning block %d has bad sequence number %d" TENDSTR),blk,sequenceNumber));
5008 // Dungy old bubble sort for now...
5011 yaffs_BlockIndex temp;
5015 for(i = 0; i < nBlocksToScan; i++)
5016 for(j = i+1; j < nBlocksToScan; j++)
5017 if(blockIndex[i].seq > blockIndex[j].seq)
5019 temp = blockIndex[j];
5020 blockIndex[j] = blockIndex[i];
5021 blockIndex[i] = temp;
5026 // Now scan the blocks looking at the data.
5030 endIterator = nBlocksToScan-1;
5031 T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("%d blocks to be scanned" TENDSTR),nBlocksToScan));
5035 // For each block.... backwards
5036 for(blockIterator = endIterator; blockIterator >= startIterator; blockIterator--)
5039 // get the block to scan in the correct order
5040 blk = blockIndex[blockIterator].block;
5043 bi = yaffs_GetBlockInfo(dev,blk);
5044 state = bi->blockState;
5048 if( 0 && // Disable since this is redundant.
5049 state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
5051 // Let's look at the first chunk in the block
5052 chunk = blk * dev->nChunksPerBlock;
5054 yaffs_ReadChunkWithTagsFromNAND(dev,chunk,NULL,&tags);
5056 // Let's have a good look at this chunk...
5060 // An unassigned chunk in the block
5061 // This means that either the block is empty or
5062 // this is the one being allocated from
5064 // We're looking at the first chunk in the block so the block is unused
5065 state = YAFFS_BLOCK_STATE_EMPTY;
5066 dev->nErasedBlocks++;
5067 dev->nFreeChunks += dev->nChunksPerBlock;
5072 // For each chunk in each block that needs scanning....
5073 for(c = dev->nChunksPerBlock-1; c >= 0 &&
5074 (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
5075 state == YAFFS_BLOCK_STATE_ALLOCATING); c--)
5077 // Scan backwards...
5078 // Read the tags and decide what to do
5079 chunk = blk * dev->nChunksPerBlock + c;
5081 yaffs_ReadChunkWithTagsFromNAND(dev,chunk,NULL,&tags);
5083 // Let's have a good look at this chunk...
5087 // An unassigned chunk in the block
5088 // This means that either the block is empty or
5089 // this is the one being allocated from
5093 // We're looking at the first chunk in the block so the block is unused
5094 state = YAFFS_BLOCK_STATE_EMPTY;
5095 dev->nErasedBlocks++;
5099 // this is the block being allocated from
5100 if(state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
5102 T(YAFFS_TRACE_SCAN,(TSTR(" Allocating from %d %d" TENDSTR),blk,c));
5104 state = YAFFS_BLOCK_STATE_ALLOCATING;
5105 dev->allocationBlock = blk;
5106 dev->allocationPage = c;
5107 dev->allocationBlockFinder = blk; // Set it to here to encourage the allocator to
5108 // go forth from here.
5109 //Yaffs2 sanity check:
5110 // This should be the one with the highest sequence number
5111 if(dev->isYaffs2 && (dev->sequenceNumber != bi->sequenceNumber))
5113 T(YAFFS_TRACE_ALWAYS,
5114 (TSTR("yaffs: Allocation block %d was not highest sequence id: block seq = %d, dev seq = %d" TENDSTR),
5115 blk,bi->sequenceNumber,dev->sequenceNumber));
5119 dev->nFreeChunks ++;
5121 else if(tags.chunkId > 0)
5123 // chunkId > 0 so it is a data chunk...
5124 unsigned int endpos;
5126 __u32 chunkBase = (tags.chunkId - 1)* dev->nBytesPerChunk;
5128 yaffs_SetChunkBit(dev,blk,c);
5131 in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,YAFFS_OBJECT_TYPE_FILE);
5132 if(in->variantType == YAFFS_OBJECT_TYPE_FILE &&
5133 chunkBase < in->variant.fileVariant.shrinkSize)
5135 // This has not been invalidated by a resize
5136 yaffs_PutChunkIntoFile(in,tags.chunkId,chunk,-1);
5139 // File size is calculated by looking at the data chunks if we have not
5140 // seen an object header yet. Stop this practice once we find an object header.
5141 endpos = (tags.chunkId - 1)* dev->nBytesPerChunk + tags.byteCount;
5142 if(!in->valid && // have not got an object header yet
5143 in->variant.fileVariant.scannedFileSize <endpos)
5145 in->variant.fileVariant.scannedFileSize = endpos;
5146 in->variant.fileVariant.fileSize = in->variant.fileVariant.scannedFileSize;
5152 // This chunk has been invalidated by a resize, so delete
5153 yaffs_DeleteChunk(dev,chunk,1,__LINE__);
5157 //T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId));
5161 // chunkId == 0, so it is an ObjectHeader.
5162 // Thus, we read in the object header and make the object
5163 yaffs_SetChunkBit(dev,blk,c);
5169 if(tags.extraHeaderInfoAvailable)
5171 in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,tags.extraObjectType);
5175 if(!in || !in->valid)
5178 // If we don't have valid info then we need to read the chunk
5179 // TODO In future we can probably defer reading the chunk and
5180 // living with invalid data until needed.
5182 yaffs_ReadChunkWithTagsFromNAND(dev,chunk,chunkData,NULL);
5184 oh = (yaffs_ObjectHeader *)chunkData;
5187 in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,oh->type);
5193 // TODO Hoosterman we have a problem!
5194 T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: Could not make object for object %d at chunk %d during scan" TENDSTR),tags.objectId,chunk));
5200 // We have already filled this one. We have a duplicate that will be discarded, but
5201 // we first have to suck out resize info if it is a file.
5203 if( (in->variantType == YAFFS_OBJECT_TYPE_FILE) &&
5204 ((oh && oh->type == YAFFS_OBJECT_TYPE_FILE) ||
5205 (tags.extraHeaderInfoAvailable && tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE))
5208 __u32 thisSize = (oh) ? oh->fileSize : tags.extraFileLength;
5209 __u32 parentObjectId = (oh) ? oh->parentObjectId : tags.extraParentObjectId;
5210 unsigned isShrink = (oh) ? oh->isShrink : tags.extraIsShrinkHeader;
5212 // If it is deleted (unlinked at start also means deleted)
5213 // we treat the file size as being zeroed at this point.
5214 if(parentObjectId == YAFFS_OBJECTID_DELETED ||
5215 parentObjectId == YAFFS_OBJECTID_UNLINKED)
5221 if(in->variant.fileVariant.shrinkSize > thisSize)
5223 in->variant.fileVariant.shrinkSize = thisSize;
5228 bi->hasShrinkHeader = 1;
5232 // Use existing - destroy this one.
5233 yaffs_DeleteChunk(dev,chunk,1,__LINE__);
5238 (tags.objectId == YAFFS_OBJECTID_ROOT ||
5239 tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))
5241 // We only load some info, don't fiddle with directory structure
5243 in->variantType = oh->type;
5245 in->st_mode = oh->st_mode;
5246 #ifdef CONFIG_YAFFS_WINCE
5247 in->win_atime[0] = oh->win_atime[0];
5248 in->win_ctime[0] = oh->win_ctime[0];
5249 in->win_mtime[0] = oh->win_mtime[0];
5250 in->win_atime[1] = oh->win_atime[1];
5251 in->win_ctime[1] = oh->win_ctime[1];
5252 in->win_mtime[1] = oh->win_mtime[1];
5254 in->st_uid = oh->st_uid;
5255 in->st_gid = oh->st_gid;
5256 in->st_atime = oh->st_atime;
5257 in->st_mtime = oh->st_mtime;
5258 in->st_ctime = oh->st_ctime;
5259 in->st_rdev = oh->st_rdev;
5261 in->chunkId = chunk;
5266 // we need to load this info
5269 in->variantType = oh->type;
5271 in->st_mode = oh->st_mode;
5272 #ifdef CONFIG_YAFFS_WINCE
5273 in->win_atime[0] = oh->win_atime[0];
5274 in->win_ctime[0] = oh->win_ctime[0];
5275 in->win_mtime[0] = oh->win_mtime[0];
5276 in->win_atime[1] = oh->win_atime[1];
5277 in->win_ctime[1] = oh->win_ctime[1];
5278 in->win_mtime[1] = oh->win_mtime[1];
5280 in->st_uid = oh->st_uid;
5281 in->st_gid = oh->st_gid;
5282 in->st_atime = oh->st_atime;
5283 in->st_mtime = oh->st_mtime;
5284 in->st_ctime = oh->st_ctime;
5285 in->st_rdev = oh->st_rdev;
5287 in->chunkId = chunk;
5289 yaffs_SetObjectName(in,oh->name);
5292 // directory stuff...
5293 // hook up to parent
5295 parent = yaffs_FindOrCreateObjectByNumber(dev,oh->parentObjectId,YAFFS_OBJECT_TYPE_DIRECTORY);
5296 if(parent->variantType == YAFFS_OBJECT_TYPE_UNKNOWN)
5298 // Set up as a directory
5299 parent->variantType = YAFFS_OBJECT_TYPE_DIRECTORY;
5300 INIT_LIST_HEAD(&parent->variant.directoryVariant.children);
5302 else if(parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
5304 // Hoosterman, another problem....
5305 // We're trying to use a non-directory as a directory
5307 T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." TENDSTR)));
5308 parent = dev->lostNFoundDir;
5311 yaffs_AddObjectToDirectory(parent,in);
5313 if((parent == dev->deletedDir ||
5314 parent == dev->unlinkedDir))
5316 in->deleted = 1; // If it is unlinked at start up then it wants deleting
5321 // Mark the block as having a shrinkHeader
5322 bi->hasShrinkHeader = 1;
5326 // Note re hardlinks.
5327 // Since we might scan a hardlink before its equivalent object is scanned
5328 // we put them all in a list.
5329 // After scanning is complete, we should have all the objects, so we run through this
5330 // list and fix up all the chains.
5332 switch(in->variantType)
5334 case YAFFS_OBJECT_TYPE_UNKNOWN: // Todo got a problem
5336 case YAFFS_OBJECT_TYPE_FILE:
5339 if(in->variant.fileVariant.scannedFileSize < oh->fileSize)
5341 in->variant.fileVariant.fileSize = oh->fileSize;
5342 in->variant.fileVariant.scannedFileSize = in->variant.fileVariant.fileSize;
5347 if(in->variant.fileVariant.shrinkSize > oh->fileSize)
5349 in->variant.fileVariant.shrinkSize = oh->fileSize;
5354 case YAFFS_OBJECT_TYPE_HARDLINK:
5355 in->variant.hardLinkVariant.equivalentObjectId = oh->equivalentObjectId;
5356 in->hardLinks.next = (struct list_head *)hardList;
5359 case YAFFS_OBJECT_TYPE_DIRECTORY: // Do nothing
5361 case YAFFS_OBJECT_TYPE_SPECIAL: // Do nothing
5363 case YAFFS_OBJECT_TYPE_SYMLINK: // Do nothing
5364 in->variant.symLinkVariant.alias = yaffs_CloneString(oh->alias);
5369 if(parent == dev->deletedDir)
5371 yaffs_DestroyObject(in);
5372 bi->hasShrinkHeader = 1;
5375 //T((" %d %d header %d \"%s\" type %d\n",blk,c,tags.objectId,oh->name,in->variantType));
5380 if(state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
5382 // If we got this far while scanning, then the block is fully allocated.
5383 state = YAFFS_BLOCK_STATE_FULL;
5386 bi->blockState = state;
5388 // Now let's see if it was dirty
5389 if( bi->pagesInUse == 0 &&
5390 !bi->hasShrinkHeader &&
5391 bi->blockState == YAFFS_BLOCK_STATE_FULL)
5393 yaffs_BlockBecameDirty(dev,blk);
5403 // Ok, we've done all the scanning.
5405 // Fix up the hard link chains.
5406 // We should now have scanned all the objects, now it's time to add these
5411 hardList = (yaffs_Object *)(hardList->hardLinks.next);
5413 in = yaffs_FindObjectByNumber(dev,hl->variant.hardLinkVariant.equivalentObjectId);
5417 // Add the hardlink pointers
5418 hl->variant.hardLinkVariant.equivalentObject=in;
5419 list_add(&hl->hardLinks,&in->hardLinks);
5423 //Todo Need to report/handle this better.
5424 // Got a problem... hardlink to a non-existant object
5425 hl->variant.hardLinkVariant.equivalentObject=NULL;
5426 INIT_LIST_HEAD(&hl->hardLinks);
5433 struct list_head *i;
5434 struct list_head *n;
5438 // Soft delete all the unlinked files
5439 list_for_each_safe(i,n,&dev->unlinkedDir->variant.directoryVariant.children)
5443 l = list_entry(i, yaffs_Object,siblings);
5444 yaffs_DestroyObject(l);
5448 // Soft delete all the deletedDir files
5449 list_for_each_safe(i,n,&dev->deletedDir->variant.directoryVariant.children)
5453 l = list_entry(i, yaffs_Object,siblings);
5454 yaffs_DestroyObject(l);
5460 yaffs_ReleaseTempBuffer(dev,chunkData,__LINE__);
5462 T(YAFFS_TRACE_SCAN,(TSTR("yaffs_ScanBackwards ends" TENDSTR)));
5469 ////////////////////////// Directory Functions /////////////////////////
5472 static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj)
5477 T(YAFFS_TRACE_ALWAYS,(TSTR("tragedy: Trying to add an object to a null pointer directory" TENDSTR)));
5480 if(directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
5482 T(YAFFS_TRACE_ALWAYS,(TSTR("tragedy: Trying to add an object to a non-directory" TENDSTR)));
5486 if(obj->siblings.prev == NULL)
5489 INIT_LIST_HEAD(&obj->siblings);
5492 else if(!list_empty(&obj->siblings))
5494 // If it is holed up somewhere else, un hook it
5495 list_del_init(&obj->siblings);
5498 list_add(&obj->siblings,&directory->variant.directoryVariant.children);
5499 obj->parent = directory;
5501 if(directory == obj->myDev->unlinkedDir || directory == obj->myDev->deletedDir)
5504 obj->myDev->nUnlinkedFiles++;
5505 obj->renameAllowed = 0;
5509 static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj)
5511 list_del_init(&obj->siblings);
5515 yaffs_Object *yaffs_FindObjectByName(yaffs_Object *directory,const YCHAR *name)
5519 struct list_head *i;
5520 YCHAR buffer[YAFFS_MAX_NAME_LENGTH+1];
5527 T(YAFFS_TRACE_ALWAYS,(TSTR("tragedy: yaffs_FindObjectByName: null pointer directory"TENDSTR)));
5530 if(directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
5532 T(YAFFS_TRACE_ALWAYS,(TSTR("tragedy: yaffs_FindObjectByName: non-directory"TENDSTR)));
5536 sum = yaffs_CalcNameSum(name);
5538 list_for_each(i,&directory->variant.directoryVariant.children)
5542 l = list_entry(i, yaffs_Object,siblings);
5544 // Special case for lost-n-found
5545 if(l->objectId == YAFFS_OBJECTID_LOSTNFOUND)
5547 if(yaffs_strcmp(name,YAFFS_LOSTNFOUND_NAME) == 0)
5552 else if(yaffs_SumCompare(l->sum, sum)||
5553 l->chunkId <= 0) //LostnFound cunk called Objxxx
5556 yaffs_GetObjectName(l,buffer,YAFFS_MAX_NAME_LENGTH);
5557 if(yaffs_strcmp(name,buffer) == 0)
5570 int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir,int (*fn)(yaffs_Object *))
5572 struct list_head *i;
5578 T(YAFFS_TRACE_ALWAYS,(TSTR("tragedy: yaffs_FindObjectByName: null pointer directory"TENDSTR)));
5581 if(theDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
5583 T(YAFFS_TRACE_ALWAYS,(TSTR("tragedy: yaffs_FindObjectByName: non-directory"TENDSTR)));
5587 list_for_each(i,&theDir->variant.directoryVariant.children)
5591 l = list_entry(i, yaffs_Object,siblings);
5604 // GetEquivalentObject dereferences any hard links to get to the
5607 yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj)
5609 if(obj && obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
5611 // We want the object id of the equivalent object, not this one
5612 obj = obj->variant.hardLinkVariant.equivalentObject;
5618 int yaffs_GetObjectName(yaffs_Object *obj,YCHAR *name,int buffSize)
5620 memset(name,0,buffSize * sizeof(YCHAR));
5622 if(obj->objectId == YAFFS_OBJECTID_LOSTNFOUND)
5624 yaffs_strncpy(name,YAFFS_LOSTNFOUND_NAME,buffSize - 1);
5626 else if(obj->chunkId <= 0)
5630 yaffs_sprintf(locName,_Y("%s%d"),YAFFS_LOSTNFOUND_PREFIX,obj->objectId);
5631 yaffs_strncpy(name,locName,buffSize - 1);
5634 #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
5635 else if(obj->shortName[0])
5637 yaffs_strcpy(name,obj->shortName);
5642 __u8 *buffer = yaffs_GetTempBuffer(obj->myDev,__LINE__);
5644 yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)buffer;
5646 memset(buffer,0,obj->myDev->nBytesPerChunk);
5648 if(obj->chunkId >= 0)
5650 yaffs_ReadChunkWithTagsFromNAND(obj->myDev,obj->chunkId,buffer,NULL);
5652 yaffs_strncpy(name,oh->name,buffSize - 1);
5654 yaffs_ReleaseTempBuffer(obj->myDev,buffer,__LINE__);
5657 return yaffs_strlen(name);
5660 int yaffs_GetObjectFileLength(yaffs_Object *obj)
5663 // Dereference any hard linking
5664 obj = yaffs_GetEquivalentObject(obj);
5666 if(obj->variantType == YAFFS_OBJECT_TYPE_FILE)
5668 return obj->variant.fileVariant.fileSize;
5670 if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
5672 return yaffs_strlen(obj->variant.symLinkVariant.alias);
5676 // Only a directory should drop through to here
5677 return obj->myDev->nBytesPerChunk;
5681 int yaffs_GetObjectLinkCount(yaffs_Object *obj)
5684 struct list_head *i;
5688 count++; // the object itself
5690 list_for_each(i,&obj->hardLinks)
5692 count++; // add the hard links;
5699 int yaffs_GetObjectInode(yaffs_Object *obj)
5701 obj = yaffs_GetEquivalentObject(obj);
5703 return obj->objectId;
5706 unsigned yaffs_GetObjectType(yaffs_Object *obj)
5708 obj = yaffs_GetEquivalentObject(obj);
5710 switch(obj->variantType)
5712 case YAFFS_OBJECT_TYPE_FILE: return DT_REG; break;
5713 case YAFFS_OBJECT_TYPE_DIRECTORY: return DT_DIR; break;
5714 case YAFFS_OBJECT_TYPE_SYMLINK: return DT_LNK; break;
5715 case YAFFS_OBJECT_TYPE_HARDLINK: return DT_REG; break;
5716 case YAFFS_OBJECT_TYPE_SPECIAL:
5717 if(S_ISFIFO(obj->st_mode)) return DT_FIFO;
5718 if(S_ISCHR(obj->st_mode)) return DT_CHR;
5719 if(S_ISBLK(obj->st_mode)) return DT_BLK;
5720 if(S_ISSOCK(obj->st_mode)) return DT_SOCK;
5721 default: return DT_REG; break;
5725 YCHAR *yaffs_GetSymlinkAlias(yaffs_Object *obj)
5727 obj = yaffs_GetEquivalentObject(obj);
5728 if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
5730 return yaffs_CloneString(obj->variant.symLinkVariant.alias);
5734 return yaffs_CloneString(_Y(""));
5738 #ifndef CONFIG_YAFFS_WINCE
5740 int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr)
5742 unsigned int valid = attr->ia_valid;
5744 if(valid & ATTR_MODE) obj->st_mode = attr->ia_mode;
5745 if(valid & ATTR_UID) obj->st_uid = attr->ia_uid;
5746 if(valid & ATTR_GID) obj->st_gid = attr->ia_gid;
5748 if(valid & ATTR_ATIME) obj->st_atime = Y_TIME_CONVERT(attr->ia_atime);
5749 if(valid & ATTR_CTIME) obj->st_ctime = Y_TIME_CONVERT(attr->ia_ctime);
5750 if(valid & ATTR_MTIME) obj->st_mtime = Y_TIME_CONVERT(attr->ia_mtime);
5752 if(valid & ATTR_SIZE) yaffs_ResizeFile(obj,attr->ia_size);
5754 yaffs_UpdateObjectHeader(obj,NULL,1,0);
5759 int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr)
5761 unsigned int valid = 0;
5763 attr->ia_mode = obj->st_mode; valid |= ATTR_MODE;
5764 attr->ia_uid = obj->st_uid; valid |= ATTR_UID;
5765 attr->ia_gid = obj->st_gid; valid |= ATTR_GID;
5767 Y_TIME_CONVERT(attr->ia_atime)= obj->st_atime; valid |= ATTR_ATIME;
5768 Y_TIME_CONVERT(attr->ia_ctime) = obj->st_ctime; valid |= ATTR_CTIME;
5769 Y_TIME_CONVERT(attr->ia_mtime) = obj->st_mtime; valid |= ATTR_MTIME;
5771 attr->ia_size = yaffs_GetFileSize(obj); valid |= ATTR_SIZE;
5773 attr->ia_valid = valid;
5781 int yaffs_DumpObject(yaffs_Object *obj)
5783 // __u8 buffer[YAFFS_BYTES_PER_CHUNK];
5785 // yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)buffer;
5787 // memset(buffer,0,YAFFS_BYTES_PER_CHUNK);
5789 // if(obj->chunkId >= 0)
5791 // yaffs_ReadChunkFromNAND(obj->myDev,obj->chunkId,buffer,NULL);
5794 yaffs_GetObjectName(obj,name,256);
5796 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),
5797 obj->objectId,yaffs_GetObjectInode(obj), name, obj->dirty, obj->valid, obj->serial,
5798 obj->sum, obj->chunkId, yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj)));
5801 YPRINTF(("Object %d \"%s\"\n dirty %d valid %d serial %d sum %d chunk %d\n",
5802 obj->objectId, oh->name, obj->dirty, obj->valid, obj->serial,
5803 obj->sum, obj->chunkId));
5804 switch(obj->variantType)
5806 case YAFFS_OBJECT_TYPE_FILE:
5807 YPRINTF((" FILE length %d\n",obj->variant.fileVariant.fileSize));
5809 case YAFFS_OBJECT_TYPE_DIRECTORY:
5810 YPRINTF((" DIRECTORY\n"));
5812 case YAFFS_OBJECT_TYPE_HARDLINK: //todo
5813 case YAFFS_OBJECT_TYPE_SYMLINK:
5814 case YAFFS_OBJECT_TYPE_UNKNOWN:
5823 ///////////////////////// Initialisation code ///////////////////////////
5826 int yaffs_CheckDevFunctions(const yaffs_Device *dev)
5829 // Common functions, gotta have
5830 if(!dev->eraseBlockInNAND ||
5831 !dev->initialiseNAND) return 0;
5833 #ifdef CONFIG_YAFFS_YAFFS2
5835 // Can use the "with tags" style interface for yaffs1 or yaffs2
5836 if(dev->writeChunkWithTagsToNAND &&
5837 dev->readChunkWithTagsFromNAND &&
5838 !dev->writeChunkToNAND &&
5839 !dev->readChunkFromNAND &&
5840 dev->markNANDBlockBad &&
5841 dev->queryNANDBlock) return 1;
5844 // Can use the "spare" style interface for yaffs1
5845 if(!dev->isYaffs2 &&
5846 !dev->writeChunkWithTagsToNAND &&
5847 !dev->readChunkWithTagsFromNAND &&
5848 dev->writeChunkToNAND &&
5849 dev->readChunkFromNAND &&
5850 !dev->markNANDBlockBad &&
5851 !dev->queryNANDBlock) return 1;
5857 int yaffs_GutsInitialise(yaffs_Device *dev)
5864 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: yaffs_GutsInitialise()" TENDSTR)));
5865 // Check stuff that must be set
5869 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Need a device" TENDSTR)));
5873 dev->internalStartBlock = dev->startBlock;
5874 dev->internalEndBlock = dev->endBlock;
5875 dev->blockOffset = 0;
5876 dev->chunkOffset = 0;
5878 if(dev->startBlock == 0)
5880 dev->internalStartBlock = dev->startBlock + 1;
5881 dev->internalEndBlock = dev->endBlock + 1;
5882 dev->blockOffset = 1;
5883 dev->chunkOffset = dev->nChunksPerBlock;
5886 // Check geometry parameters.
5888 if( (dev->isYaffs2 && dev->nBytesPerChunk <1024) ||
5889 (!dev->isYaffs2 && dev->nBytesPerChunk !=512) ||
5890 dev->nChunksPerBlock < 2 ||
5891 dev->nReservedBlocks < 2 ||
5892 dev->internalStartBlock <= 0 ||
5893 dev->internalEndBlock <= 0 ||
5894 dev->internalEndBlock <= (dev->internalStartBlock + dev->nReservedBlocks + 2) // otherwise it is too small
5897 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s " TENDSTR),
5898 dev->nBytesPerChunk, dev->isYaffs2 ? "2" : ""));
5902 if(yaffs_InitialiseNAND(dev) != YAFFS_OK)
5904 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: InitialiseNAND failed" TENDSTR)));
5908 // Got the right mix of functions?
5910 if(!yaffs_CheckDevFunctions(dev))
5913 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: device function(s) missing or wrong\n" TENDSTR)));
5918 // This is really a compilation check.
5919 if(!yaffs_CheckStructures())
5921 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs_CheckStructures failed\n" TENDSTR)));
5927 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: device already mounted\n" TENDSTR)));
5933 // Finished with most checks. One or two more checks happen later on too.
5939 nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
5943 // OK now calculate a few things for the device
5944 // Calculate chunkGroupBits.
5945 // We need to find the next power of 2 > than internalEndBlock
5947 x = dev->nChunksPerBlock * (dev->internalEndBlock+1);
5949 for(bits = extraBits = 0; x > 1; bits++)
5951 if(x & 1) extraBits++;
5955 if(extraBits > 0) bits++;
5958 // Level0 Tnodes are 16 bits, so if the bitwidth of the
5959 // chunk range we're using is greater than 16 we need
5960 // to figure out chunk shift and chunkGroupSize
5963 dev->chunkGroupBits = 0;
5967 dev->chunkGroupBits = bits - 16;
5970 dev->chunkGroupSize = 1 << dev->chunkGroupBits;
5972 if(dev->nChunksPerBlock < dev->chunkGroupSize)
5974 // We have a problem because the soft delete won't work if
5975 // the chunk group size > chunks per block.
5976 // This can be remedied by using larger "virtual blocks".
5977 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: chunk group too large\n" TENDSTR)));
5983 // OK, we've finished verifying the device, lets continue with initialisation
5985 // More device initialisation
5986 dev->garbageCollections = 0;
5987 dev->passiveGarbageCollections = 0;
5988 dev->currentDirtyChecker = 0;
5989 dev->bufferedBlock = -1;
5990 dev->doingBufferedBlockRewrite = 0;
5991 dev->nDeletedFiles = 0;
5992 dev->nBackgroundDeletions=0;
5993 dev->nUnlinkedFiles = 0;
5996 dev->tagsEccFixed=0;
5997 dev->tagsEccUnfixed=0;
5998 dev->nErasureFailures = 0;
5999 dev->nErasedBlocks = 0;
6001 //dev->localBuffer = YMALLOC(dev->nBytesPerChunk);
6002 // Initialise temporary buffers
6005 for(i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
6007 dev->tempBuffer[i].line = 0; // not in use
6008 dev->tempBuffer[i].buffer = YMALLOC(dev->nBytesPerChunk);
6014 yaffs_InitialiseBlocks(dev,nBlocks);
6016 yaffs_InitialiseTnodes(dev);
6018 yaffs_InitialiseObjects(dev);
6020 dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32));
6022 if(dev->nShortOpCaches > 0)
6026 if(dev->nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES)
6028 dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES;
6031 dev->srCache = YMALLOC( dev->nShortOpCaches * sizeof(yaffs_ChunkCache));
6033 for(i=0; i < dev->nShortOpCaches; i++)
6035 dev->srCache[i].object = NULL;
6036 dev->srCache[i].lastUse = 0;
6037 dev->srCache[i].dirty = 0;
6038 dev->srCache[i].data = YMALLOC(dev->nBytesPerChunk);
6046 // Initialise the unlinked, root and lost and found directories
6047 dev->lostNFoundDir = dev->rootDir = dev->unlinkedDir = dev->deletedDir = NULL;
6049 dev->unlinkedDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_UNLINKED, S_IFDIR);
6050 dev->deletedDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_DELETED, S_IFDIR);
6052 dev->rootDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_ROOT,YAFFS_ROOT_MODE | S_IFDIR);
6053 dev->lostNFoundDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_LOSTNFOUND,YAFFS_LOSTNFOUND_MODE | S_IFDIR);
6054 yaffs_AddObjectToDirectory(dev->rootDir,dev->lostNFoundDir);
6058 dev->useHeaderFileSize = 1;
6061 // Now scan the flash.
6064 yaffs_ScanBackwards(dev);
6069 dev->nPageReads = 0;
6070 dev->nPageWrites = 0;
6071 dev->nBlockErasures = 0;
6073 dev->nRetriedWrites = 0;
6075 dev->nRetiredBlocks = 0;
6077 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));
6082 void yaffs_Deinitialise(yaffs_Device *dev)
6088 yaffs_DeinitialiseBlocks(dev);
6089 yaffs_DeinitialiseTnodes(dev);
6090 yaffs_DeinitialiseObjects(dev);
6091 if(dev->nShortOpCaches > 0)
6094 for(i=0; i < dev->nShortOpCaches; i++)
6096 YFREE(dev->srCache[i].data);
6099 YFREE(dev->srCache);
6102 YFREE(dev->gcCleanupList);
6104 for(i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
6106 YFREE(dev->tempBuffer[i].buffer);
6116 int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
6118 int nFree = dev->nFreeChunks - (dev->nChunksPerBlock * YAFFS_RESERVED_BLOCKS);
6120 struct list_head *i;
6124 // To the free chunks add the chunks that are in the deleted unlinked files.
6125 list_for_each(i,&dev->deletedDir->variant.directoryVariant.children)
6127 l = list_entry(i, yaffs_Object,siblings);
6131 nFree += l->nDataChunks;
6136 // printf("___________ nFreeChunks is %d nFree is %d\n",dev->nFreeChunks,nFree);
6138 if(nFree < 0) nFree = 0;
6146 int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
6151 int nDirtyCacheChunks=0;
6153 yaffs_BlockInfo *blk;
6155 struct list_head *i;
6158 for(nFree = 0, b = dev->internalStartBlock; b <= dev->internalEndBlock; b++)
6160 blk = yaffs_GetBlockInfo(dev,b);
6162 switch(blk->blockState)
6164 case YAFFS_BLOCK_STATE_EMPTY:
6165 case YAFFS_BLOCK_STATE_ALLOCATING:
6166 case YAFFS_BLOCK_STATE_FULL: nFree += (dev->nChunksPerBlock - blk->pagesInUse); break;
6174 // To the free chunks add the chunks that are in the deleted unlinked files.
6175 list_for_each(i,&dev->deletedDir->variant.directoryVariant.children)
6179 l = list_entry(i, yaffs_Object,siblings);
6183 pending += l->nDataChunks;
6190 //printf("___________ really free is %d, pending %d, nFree is %d\n",nFree,pending, nFree+pending);
6192 if(nFree != dev->nFreeChunks)
6194 // printf("___________Different! really free is %d, nFreeChunks %d\n",nFree dev->nFreeChunks);
6199 // Now count the number of dirty chunks in the cache and subtract those
6203 for(i = 0; i < dev->nShortOpCaches; i++)
6205 if(dev->srCache[i].dirty) nDirtyCacheChunks++;
6209 nFree -= nDirtyCacheChunks;
6211 nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock);
6213 if(nFree < 0) nFree = 0;
6221 /////////////////// YAFFS test code //////////////////////////////////
6223 #define yaffs_CheckStruct(structure,syze, name) \
6224 if(sizeof(structure) != syze) \
6226 T(YAFFS_TRACE_ALWAYS,(TSTR("%s should be %d but is %d\n" TENDSTR),name,syze,sizeof(structure))); \
6227 return YAFFS_FAIL; \
6231 static int yaffs_CheckStructures(void)
6233 // yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags")
6234 // yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion")
6235 // yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare")
6236 #ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG
6237 yaffs_CheckStruct(yaffs_Tnode,2* YAFFS_NTNODES_LEVEL0,"yaffs_Tnode")
6239 yaffs_CheckStruct(yaffs_ObjectHeader,512,"yaffs_ObjectHeader")
6246 void yaffs_GutsTest(yaffs_Device *dev)
6249 if(yaffs_CheckStructures() != YAFFS_OK)
6251 T(YAFFS_TRACE_ALWAYS,(TSTR("One or more structures malformed-- aborting\n" TENDSTR)));
6255 yaffs_TnodeTest(dev);
6256 yaffs_ObjectTest(dev);