-
/*
* YAFFS: Yet another FFS. A NAND-flash specific file system.
*
*/
//yaffs_guts.c
-const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.8 2005-07-05 23:54:59 charles Exp $";
+const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.17 2005-08-09 04:17:30 charles Exp $";
#include "yportenv.h"
#define YAFFS_PASSIVE_GC_CHUNKS 2
-#if 0
-// Use Steven Hill's ECC struff instead
-// External functions for ECC on data
-void nand_calculate_ecc (const u_char *dat, u_char *ecc_code);
-int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc);
-#define yaffs_ECCCalculate(data,ecc) nand_calculate_ecc(data,ecc)
-#define yaffs_ECCCorrect(data,read_ecc,calc_ecc) nand_correct_ecc(data,read_ecc,calc_ecc)
-#else
-#include "yaffs_ecc.h"
-#endif
-
-#if 0
-// countBits is a quick way of counting the number of bits in a byte.
-// ie. countBits[n] holds the number of 1 bits in a byte with the value n.
-
-static const char yaffs_countBitsTable[256] =
-{
-0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,
-1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
-1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
-2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
-1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
-2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
-2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
-3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
-1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
-2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
-2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
-3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
-2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
-3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
-3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
-4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8
-};
-
-static int yaffs_CountBits(__u8 x)
-{
- int retVal;
- retVal = yaffs_countBitsTable[x];
- return retVal;
-}
-
-#endif
+#include "yaffs_ecc.h"
-#if 0
-// Stuff using yea olde tags
-static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr);
-static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr);
-static int yaffs_ReadChunkTagsFromNAND(yaffs_Device *dev,int chunkInNAND, yaffs_Tags *tags, int *chunkDeleted);
-static int yaffs_TagsMatch(const yaffs_Tags *tags, int objectId, int chunkInObject, int chunkDeleted);
-#else
-#endif
// NAND access
static Y_INLINE int yaffs_QueryInitialBlockState(yaffs_Device *dev,int blockNo, yaffs_BlockState *state,unsigned *sequenceNumber);
// Local prototypes
static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, const __u8 *buffer, yaffs_ExtendedTags *tags, int useReserve);
-#if 0
-static int yaffs_CheckObjectHashSanity(yaffs_Device *dev);
-#endif
static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan);
static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type);
static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj);
-static int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int isShrink);
+static int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int isShrink, int shadows);
static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj);
static int yaffs_CheckStructures(void);
static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset,int *limit);
// Robustification (if it ever comes about...)
static void yaffs_RetireBlock(yaffs_Device *dev,int blockInNAND);
-#if 0
-static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND);
-#endif
static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND);
static void yaffs_HandleWriteChunkOk(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *tags);
static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND, const yaffs_ExtendedTags *tags);
static int yaffs_UnlinkWorker(yaffs_Object *obj);
static void yaffs_DestroyObject(yaffs_Object *obj);
-#if 0
-static int yaffs_VerifyCompare(const __u8 *d0, const __u8 * d1, const yaffs_Spare *s0, const yaffs_Spare *s1,int dataSize);
-#endif
static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId, int chunkInObject);
static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve);
+static void yaffs_VerifyFreeChunks(yaffs_Device *dev);
+
#ifdef YAFFS_PARANOID
static int yaffs_CheckFileSanity(yaffs_Object *in);
#else
return yaffs_TagsCompatabilityQueryNANDBlock(dev,blockNo,state,sequenceNumber);
}
-int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND)
+static int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND)
{
int result;
-#if 1
static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, const __u8 *data, yaffs_ExtendedTags *tags,int useReserve)
{
int chunk;
return chunk;
}
-#endif
+
///
}
-#if 0
-static int yaffs_RewriteBufferedBlock(yaffs_Device *dev)
-{
- dev->doingBufferedBlockRewrite = 1;
- //
- // Remove erased chunks
- // Rewrite existing chunks to a new block
- // Set current write block to the new block
-
- dev->doingBufferedBlockRewrite = 0;
-
- return 1;
-}
-
-
-static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND)
-{
- int blockInNAND = chunkInNAND/dev->nChunksPerBlock;
-
- // Mark the block for retirement
- yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1;
- T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>>Block %d marked for retirement" TENDSTR),blockInNAND));
-
-
- //TODO
- // Just do a garbage collection on the affected block then retire the block
- // NB recursion
-}
-
-
-static void yaffs_CheckWrittenBlock(yaffs_Device *dev,int chunkInNAND)
-{
-}
-
-#endif
static void yaffs_HandleWriteChunkOk(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *tags)
{
-#if 0
-static int yaffs_VerifyCompare(const __u8 *d0, const __u8 * d1, const yaffs_Spare *s0, const yaffs_Spare *s1,int dataSize)
-{
-
-
- if( memcmp(d0,d1,dataSize) != 0 ||
- s0->tagByte0 != s1->tagByte0 ||
- s0->tagByte1 != s1->tagByte1 ||
- s0->tagByte2 != s1->tagByte2 ||
- s0->tagByte3 != s1->tagByte3 ||
- s0->tagByte4 != s1->tagByte4 ||
- s0->tagByte5 != s1->tagByte5 ||
- s0->tagByte6 != s1->tagByte6 ||
- s0->tagByte7 != s1->tagByte7 ||
- s0->ecc1[0] != s1->ecc1[0] ||
- s0->ecc1[1] != s1->ecc1[1] ||
- s0->ecc1[2] != s1->ecc1[2] ||
- s0->ecc2[0] != s1->ecc2[0] ||
- s0->ecc2[1] != s1->ecc2[1] ||
- s0->ecc2[2] != s1->ecc2[2] )
- {
- return 0;
- }
-
- return 1;
-}
-#endif
-
-
///////////////////////// Object management //////////////////
// List of spare objects
// The list is hooked together using the first pointer
return sum;
}
-void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)
+static void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)
{
#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
if(name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH)
obj->sum = yaffs_CalcNameSum(name);
}
-#if 0
-void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare)
-{
- yaffs_ECCCalculate(data , spare->ecc1);
- yaffs_ECCCalculate(&data[256] , spare->ecc2);
-}
-#endif
///////////////////////// TNODES ///////////////////////
{
newTnodes[i].internal[0] = &newTnodes[i+1];
#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
- newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = 1;
+ newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
#endif
}
newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes;
#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
- newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = 1;
+ newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
#endif
dev->freeTnodes = newTnodes;
dev->nFreeTnodes+= nTnodes;
{
tn = dev->freeTnodes;
#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
- if(tn->internal[YAFFS_NTNODES_INTERNAL] != 1)
+ if(tn->internal[YAFFS_NTNODES_INTERNAL] != (void *)1)
{
// Hoosterman, this thing looks like it isn't in the list
T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Tnode list bug 1" TENDSTR)));
// Hoosterman, this thing looks like it is already in the list
T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Tnode list bug 2" TENDSTR)));
}
- tn->internal[YAFFS_NTNODES_INTERNAL] = 1;
+ tn->internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
#endif
tn->internal[0] = dev->freeTnodes;
dev->freeTnodes = tn;
}
-#if 0
-void yaffs_TnodeTest(yaffs_Device *dev)
-{
-
- int i;
- int j;
- yaffs_Tnode *tn[1000];
-
- YINFO("Testing TNodes");
-
- for(j = 0; j < 50; j++)
- {
- for(i = 0; i < 1000; i++)
- {
- tn[i] = yaffs_GetTnode(dev);
- if(!tn[i])
- {
- YALERT("Getting tnode failed");
- }
- }
- for(i = 0; i < 1000; i+=3)
- {
- yaffs_FreeTnode(dev,tn[i]);
- tn[i] = NULL;
- }
-
- }
-}
-#endif
////////////////// END OF TNODE MANIPULATION ///////////////////////////
}
-int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk, yaffs_ExtendedTags *tags, int objectId, int chunkInInode)
+static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk, yaffs_ExtendedTags *tags, int objectId, int chunkInInode)
{
int j;
if(theBlock)
{
theBlock->softDeletions++;
+ dev->nFreeChunks++;
}
}
obj->unlinkAllowed= 0; // ... or unlink it
obj->deleted = 0;
obj->unlinked = 0;
- obj->st_mode = mode;
+ obj->yst_mode = mode;
obj->myDev = dev;
obj->chunkId = 0; // Not a valid chunk.
}
-int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
+static int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
{
static int x = 0;
int i;
return n;
}
-void yaffs_HashObject(yaffs_Object *in)
+static void yaffs_HashObject(yaffs_Object *in)
{
int bucket = yaffs_HashFunction(in->objectId);
yaffs_Device *dev = in->myDev;
#else
- theObject->st_atime = theObject->st_mtime = theObject->st_ctime = Y_CURRENT_TIME;
+ theObject->yst_atime = theObject->yst_mtime = theObject->yst_ctime = Y_CURRENT_TIME;
#endif
switch(type)
{
return theObject;
}
-yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, int number,yaffs_ObjectType type)
+static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, int number,yaffs_ObjectType type)
{
yaffs_Object *theObject = NULL;
}
-YCHAR *yaffs_CloneString(const YCHAR *str)
+static YCHAR *yaffs_CloneString(const YCHAR *str)
{
YCHAR *newStr = NULL;
// equivalentObject only has meaning for a hard link;
// aliasString only has meaning for a sumlink.
// rdev only has meaning for devices (a subset of special objects)
-yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type,
+static yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type,
yaffs_Object *parent,
const YCHAR *name,
__u32 mode,
in->valid = 1;
in->variantType = type;
- in->st_mode = mode;
+ in->yst_mode = mode;
#ifdef CONFIG_YAFFS_WINCE
yfsd_WinFileTimeNow(in->win_atime);
in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
#else
- in->st_atime = in->st_mtime = in->st_ctime = Y_CURRENT_TIME;
+ in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;
- in->st_rdev = rdev;
- in->st_uid = uid;
- in->st_gid = gid;
+ in->yst_rdev = rdev;
+ in->yst_uid = uid;
+ in->yst_gid = gid;
#endif
in->nDataChunks = 0;
}
if(/*yaffs_GetNumberOfFreeChunks(dev) <= 0 || */
- yaffs_UpdateObjectHeader(in,name,0,0) < 0)
+ yaffs_UpdateObjectHeader(in,name,0,0,0) < 0)
{
// Could not create the object header, fail the creation
yaffs_DestroyObject(in);
}
-static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const YCHAR *newName,int force)
+static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const YCHAR *newName,int force,int shadows)
{
int unlinkOp;
int deleteOp;
+
+ yaffs_Object * existingTarget;
if(newDir == NULL)
{
deleteOp = (newDir == obj->myDev->deletedDir);
+ existingTarget = yaffs_FindObjectByName(newDir,newName);
+
// If the object is a file going into the unlinked directory, then it is OK to just stuff it in since
// duplicate names are allowed.
// Otherwise only proceed if the new name does not exist and if we're putting it into a directory.
if( (unlinkOp||
deleteOp ||
force ||
- !yaffs_FindObjectByName(newDir,newName)) &&
+ (shadows > 0) ||
+ !existingTarget) &&
newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
{
yaffs_SetObjectName(obj,newName);
if(unlinkOp) obj->unlinked = 1;
// If it is a deletion then we mark it as a shrink for gc purposes.
- if(yaffs_UpdateObjectHeader(obj,newName,0,deleteOp) >= 0)
+ if(yaffs_UpdateObjectHeader(obj,newName,0,deleteOp,shadows) >= 0)
{
return YAFFS_OK;
}
int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName, yaffs_Object *newDir, const YCHAR *newName)
{
yaffs_Object *obj;
+ yaffs_Object *existingTarget;
int force = 0;
#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
#endif
obj = yaffs_FindObjectByName(oldDir,oldName);
- if(obj && obj->renameAllowed)
- {
- return yaffs_ChangeObjectName(obj,newDir,newName,force);
- }
- return YAFFS_FAIL;
-}
-
-
-#if 0
-
-static int yaffs_CheckObjectHashSanity(yaffs_Device *dev)
-{
- // Scan the buckets and check that the lists
- // have as many members as the count says there are
- int bucket;
- int countEm;
- struct list_head *j;
- int ok = YAFFS_OK;
- for(bucket = 0; bucket < YAFFS_NOBJECT_BUCKETS; bucket++)
+ if(obj && obj->renameAllowed)
{
- countEm = 0;
-
- list_for_each(j,&dev->objectBucket[bucket].list)
- {
- countEm++;
- }
-
- if(countEm != dev->objectBucket[bucket].count)
- {
- T(YAFFS_TRACE_ERROR,(TSTR("Inode hash inconsistency" TENDSTR)));
- ok = YAFFS_FAIL;
- }
- }
-
- return ok;
-}
-
-
-void yaffs_ObjectTest(yaffs_Device *dev)
-{
- yaffs_Object *in[1000];
- int inNo[1000];
- yaffs_Object *inold[1000];
- int i;
- int j;
-
- memset(in,0,1000*sizeof(yaffs_Object *));
- memset(inold,0,1000*sizeof(yaffs_Object *));
- yaffs_CheckObjectHashSanity(dev);
+ // Now do the handling for an existing target, if there is one
- for(j = 0; j < 10; j++)
- {
- //T(("%d\n",j));
+ existingTarget = yaffs_FindObjectByName(newDir,newName);
+ if(existingTarget &&
+ existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
+ !list_empty(&existingTarget->variant.directoryVariant.children))
+ {
+ // There is a target that is a non-empty directory, so we have to fail
+ return YAFFS_FAIL; // EEXIST or ENOTEMPTY
+ }
+ else if(existingTarget &&
+ existingTarget != obj)
+ {
+ // Nuke the target first, using shadowing,
+ // but only if it isn't the same object
+ yaffs_ChangeObjectName(obj,newDir,newName,force,existingTarget->objectId);
+ yaffs_Unlink(newDir,newName);
+ }
- for(i = 0; i < 1000; i++)
- {
- in[i] = yaffs_CreateNewObject(dev,-1,YAFFS_OBJECT_TYPE_FILE);
- if(!in[i])
- {
- YINFO("No more inodes");
- }
- else
- {
- inNo[i] = in[i]->objectId;
- }
- }
-
- for(i = 0; i < 1000; i++)
- {
- if(yaffs_FindObjectByNumber(dev,inNo[i]) != in[i])
- {
- //T(("Differnce in look up test\n"));
- }
- else
- {
- // T(("Look up ok\n"));
- }
- }
-
- yaffs_CheckObjectHashSanity(dev);
-
- for(i = 0; i < 1000; i+=3)
- {
- yaffs_FreeObject(in[i]);
- in[i] = NULL;
- }
-
- yaffs_CheckObjectHashSanity(dev);
+ return yaffs_ChangeObjectName(obj,newDir,newName,force,0);
}
-
+ return YAFFS_FAIL;
}
-#endif
+
/////////////////////////// Block Management and Page Allocation ///////////////////
}
pagesInUse = (aggressive)? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1;
+
if(aggressive)
{
iterations = dev->internalEndBlock - dev->internalStartBlock + 1;
}
else
{
+ dev->nFreeChunks -= dev->nChunksPerBlock; // We lost a block of free space
+
yaffs_RetireBlock(dev,blockNo);
T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>> Block %d retired" TENDSTR),blockNo));
}
}
-#if 0
-static void yaffs_DumpBlockStats(yaffs_Device *dev)
-{
- int i,j;
- yaffs_BlockInfo *bi;
-
- for(i= dev->internalStartBlock; i <=dev->internalEndBlock; i++)
- {
- bi = yaffs_GetBlockInfo(dev,i);
- T(YAFFS_TRACE_ALLOCATE,(TSTR("%3d state %d shrink %d inuse %d/%d seq %d pages"),i,
- bi->blockState,bi->hasShrinkHeader,bi->pagesInUse,bi->softDeletions,bi->sequenceNumber));
-
- for(j = 0; j < dev->nChunksPerBlock; j++)
- {
- if(yaffs_CheckChunkBit(dev,i,j))
- {
- T(YAFFS_TRACE_ALLOCATE,(TSTR(" %d"),j));
-
- }
- }
- T(YAFFS_TRACE_ALLOCATE,(TSTR(" " TENDSTR)));
-
- }
-}
-#endif
-
static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
{
int i;
yaffs_BlockInfo *bi;
-
-#if 0
- static int j = 0;
- j++;
- if(j < 0 || j > 100)
- {
- j = 0;
- yaffs_DumpBlockStats(dev);
- }
-
-#endif
-
+
if(dev->nErasedBlocks < 1)
{
// Hoosterman we've got a problem.
}
+// To determine if we have enough space we just look at the
+// number of erased blocks.
+
+static int yaffs_CheckSpaceForAllocation(yaffs_Device *dev)
+{
+ int reservedChunks = (dev->nReservedBlocks * dev->nChunksPerBlock);
+ return (dev->nFreeChunks > reservedChunks);
+}
+
static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve)
{
dev->allocationPage = 0;
}
- if(!useReserve && dev->nErasedBlocks </*=*/ dev->nReservedBlocks)
+ if(!useReserve && !yaffs_CheckSpaceForAllocation(dev))
{
// Not enough space to allocate unless we're allowed to use the reserve.
return -1;
}
-// To determine if we have enough space we just look at the
-// number of erased blocks.
-// The cache is allowed to use reserved blocks.
-
-static int yaffs_CheckSpaceForChunkCache(yaffs_Device *dev)
-{
- return (dev->nErasedBlocks >= dev->nReservedBlocks);
-}
static int yaffs_GetErasedChunks(yaffs_Device *dev)
}
-int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
+static int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
{
int oldChunk;
int newChunk;
T(YAFFS_TRACE_TRACING,(TSTR("Collecting block %d, in use %d, shrink %d, " TENDSTR),block,bi->pagesInUse,bi->hasShrinkHeader));
//T(("Collecting block %d n %d bits %x\n",block, bi->pagesInUse, bi->pageBits));
+
+ //yaffs_VerifyFreeChunks(dev);
bi->hasShrinkHeader = 0; // clear the flag so that the block can erase
+
+ dev->nFreeChunks -= bi->softDeletions; // Take off the number of soft deleted entries because
+ // they're going to get really deleted during GC.
+ dev->isDoingGC = 1;
if(!yaffs_StillSomeChunkBits(dev,block))
{
else
{
- __u8 *buffer = yaffs_GetTempBuffer(dev,__LINE__);
+ __u8 *buffer = yaffs_GetTempBuffer(dev,__LINE__);
for(chunkInBlock = 0,oldChunk = block * dev->nChunksPerBlock;
chunkInBlock < dev->nChunksPerBlock && yaffs_StillSomeChunkBits(dev,block);
if(object && object->deleted && tags.chunkId != 0)
{
// Data chunk in a deleted file, throw it away
- // It's a deleted data chunk,
+ // It's a soft deleted data chunk,
// No need to copy this, just forget about it and fix up the
// object.
tags.serialNumber++;
dev->nGCCopies++;
+
+ if(tags.chunkId == 0)
+ {
+ // It is an object Id,
+ // We need to nuke the shrinkheader flags first
+ // We no longer want the shrinkHeader flag since its work is done
+ // and if it is left in place it will mess up scanning.
+ // Also, clear out any shadowing stuff
+
+ yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)buffer;
+ oh->isShrink = 0;
+ oh->shadowsObject = -1;
+ tags.extraShadows = 0;
+ tags.extraIsShrinkHeader = 0;
+ }
newChunk = yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags,1);
yaffs_ReleaseTempBuffer(dev,buffer,__LINE__);
+ //yaffs_VerifyFreeChunks(dev);
// Do any required cleanups
for(i = 0; i < cleanups; i++)
{
T(YAFFS_TRACE_GC,(TSTR("gc did not increase free chunks before %d after %d" TENDSTR),chunksBefore,chunksAfter));
}
+
+
+ dev->isDoingGC = 0;
+
+ //yaffs_VerifyFreeChunks(dev);
return YAFFS_OK;
}
-#if 0
-static yaffs_Object *yaffs_FindDeletedUnlinkedFile(yaffs_Device *dev)
-{
- // find a file to delete
- struct list_head *i;
- yaffs_Object *l;
-
-
- //Scan the unlinked files looking for one to delete
- list_for_each(i,&dev->unlinkedDir->variant.directoryVariant.children)
- {
- if(i)
- {
- l = list_entry(i, yaffs_Object,siblings);
- if(l->deleted)
- {
- return l;
- }
- }
- }
- return NULL;
-}
-
-
-static void yaffs_DoUnlinkedFileDeletion(yaffs_Device *dev)
-{
- // This does background deletion on unlinked files.. only deleted ones.
- // If we don't have a file we're working on then find one
- if(!dev->unlinkedDeletion && dev->nDeletedFiles > 0)
- {
- dev->unlinkedDeletion = yaffs_FindDeletedUnlinkedFile(dev);
- }
-
- // OK, we're working on a file...
- if(dev->unlinkedDeletion)
- {
- yaffs_Object *obj = dev->unlinkedDeletion;
- int delresult;
- int limit; // Number of chunks to delete in a file.
- // NB this can be exceeded, but not by much.
-
- limit = -1;
-
- delresult = yaffs_DeleteWorker(obj, obj->variant.fileVariant.top, obj->variant.fileVariant.topLevel, 0,&limit);
-
- if(obj->nDataChunks == 0)
- {
- // Done all the deleting of data chunks.
- // Now dump the header and clean up
- yaffs_FreeTnode(dev,obj->variant.fileVariant.top);
- obj->variant.fileVariant.top = NULL;
- yaffs_DoGenericObjectDeletion(obj);
- dev->nDeletedFiles--;
- dev->nUnlinkedFiles--;
- dev->nBackgroundDeletions++;
- dev->unlinkedDeletion = NULL;
- }
- }
-}
-
-#endif
-
-
// New garbage collector
// If we're very low on erased blocks then we do aggressive garbage collection
// The idea is to help clear out space in a more spread-out manner.
// Dunno if it really does anything useful.
//
-int yaffs_CheckGarbageCollection(yaffs_Device *dev)
+static int yaffs_CheckGarbageCollection(yaffs_Device *dev)
{
int block;
int aggressive;
int gcOk = YAFFS_OK;
int maxTries = 0;
- //yaffs_DoUnlinkedFileDeletion(dev);
+ //yaffs_VerifyFreeChunks(dev);
+
+ if(dev->isDoingGC)
+ {
+ // Bail out so we don't get recursive gc
+ return YAFFS_OK;
+ }
// This loop should pass the first time.
// We'll only see looping here if the erase of the collected block fails.
do{
maxTries++;
- if(dev->nErasedBlocks <= (dev->nReservedBlocks + 2))
+ if(dev->nErasedBlocks < dev->nReservedBlocks)
{
// We need a block soon...
aggressive = 1;
gcOk = yaffs_GarbageCollectBlock(dev,block);
}
- if(dev->nErasedBlocks <= (dev->nReservedBlocks + 1))
+ if(dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0)
{
T(YAFFS_TRACE_GC,(TSTR("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d" TENDSTR),dev->nErasedBlocks,maxTries,block));
}
- } while((dev->nErasedBlocks <= (dev->nReservedBlocks + 1)) && (block > 0) && (maxTries < 5));
+ } while((dev->nErasedBlocks < dev->nReservedBlocks) && (block > 0) && (maxTries < 2));
return aggressive ? gcOk: YAFFS_OK;
}
-#if 0
-
-void yaffs_CalcTagsECC(yaffs_Tags *tags)
-{
- // Calculate an ecc
-
- unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
- unsigned i,j;
- unsigned ecc = 0;
- unsigned bit = 0;
-
- tags->ecc = 0;
-
- for(i = 0; i < 8; i++)
- {
- for(j = 1; j &0xff; j<<=1)
- {
- bit++;
- if(b[i] & j)
- {
- ecc ^= bit;
- }
- }
- }
-
- tags->ecc = ecc;
-
-
-}
-
-int yaffs_CheckECCOnTags(yaffs_Tags *tags)
-{
- unsigned ecc = tags->ecc;
-
- yaffs_CalcTagsECC(tags);
-
- ecc ^= tags->ecc;
-
- if(ecc && ecc <= 64)
- {
- // TODO: Handle the failure better. Retire?
- unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
-
- ecc--;
-
- b[ecc / 8] ^= (1 << (ecc & 7));
-
- // Now recvalc the ecc
- yaffs_CalcTagsECC(tags);
-
- return 1; // recovered error
- }
- else if(ecc)
- {
- // Wierd ecc failure value
- // TODO Need to do somethiong here
- return -1; //unrecovered error
- }
-
- return 0;
-}
-
-static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr)
-{
- yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr;
-
- yaffs_CalcTagsECC(tagsPtr);
-
- sparePtr->tagByte0 = tu->asBytes[0];
- sparePtr->tagByte1 = tu->asBytes[1];
- sparePtr->tagByte2 = tu->asBytes[2];
- sparePtr->tagByte3 = tu->asBytes[3];
- sparePtr->tagByte4 = tu->asBytes[4];
- sparePtr->tagByte5 = tu->asBytes[5];
- sparePtr->tagByte6 = tu->asBytes[6];
- sparePtr->tagByte7 = tu->asBytes[7];
-}
-
-static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr)
-{
- yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr;
- int result;
-
- tu->asBytes[0]= sparePtr->tagByte0;
- tu->asBytes[1]= sparePtr->tagByte1;
- tu->asBytes[2]= sparePtr->tagByte2;
- tu->asBytes[3]= sparePtr->tagByte3;
- tu->asBytes[4]= sparePtr->tagByte4;
- tu->asBytes[5]= sparePtr->tagByte5;
- tu->asBytes[6]= sparePtr->tagByte6;
- tu->asBytes[7]= sparePtr->tagByte7;
-
- result = yaffs_CheckECCOnTags(tagsPtr);
- if(result> 0)
- {
- dev->tagsEccFixed++;
- }
- else if(result <0)
- {
- dev->tagsEccUnfixed++;
- }
-}
-
-static void yaffs_SpareInitialise(yaffs_Spare *spare)
-{
- memset(spare,0xFF,sizeof(yaffs_Spare));
-}
-
-#endif
-
-#if 0
-static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, const __u8 *buffer, yaffs_ExtendedTags *tags, int useReserve)
-{
- // NB There must be tags, data is optional
- // If there is data, then an ECC is calculated on it.
-
- yaffs_Spare spare;
-
- if(!tags)
- {
- return YAFFS_FAIL;
- }
-
- //yaffs_SpareInitialise(&spare);
-
- //if(!dev->useNANDECC && buffer)
- //{
- // yaffs_CalcECC(buffer,&spare);
- //}
-
- //yaffs_LoadTagsIntoSpare(&spare,tags);
-
- return yaffs_WriteNewChunkToNAND(dev,buffer,&spare,useReserve);
-
-}
-#endif
-
static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId, int chunkInObject)
{
return ( tags->chunkId == chunkInObject &&
/////////////////////////////////////////////////////////////////////////////////////////////////////////
-int yaffs_FindChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags *tags)
+static int yaffs_FindChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags *tags)
{
//Get the Tnode, then get the level 0 offset chunk offset
yaffs_Tnode *tn;
return retVal;
}
-int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags *tags)
+static int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags *tags)
{
//Get the Tnode, then get the level 0 offset chunk offset
yaffs_Tnode *tn;
-int yaffs_ReadChunkDataFromObject(yaffs_Object *in,int chunkInInode, __u8 *buffer)
+static int yaffs_ReadChunkDataFromObject(yaffs_Object *in,int chunkInInode, __u8 *buffer)
{
int chunkInNAND = yaffs_FindChunkInFile(in,chunkInInode,NULL);
bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
bi->blockState == YAFFS_BLOCK_STATE_COLLECTING)
{
- dev->nFreeChunks++;
+ dev->nFreeChunks++;
yaffs_ClearChunkBit(dev,block,page);
+
bi->pagesInUse--;
if(bi->pagesInUse == 0 &&
-int yaffs_WriteChunkDataToObject(yaffs_Object *in,int chunkInInode, const __u8 *buffer,int nBytes,int useReserve)
+static int yaffs_WriteChunkDataToObject(yaffs_Object *in,int chunkInInode, const __u8 *buffer,int nBytes,int useReserve)
{
// Find old chunk Need to do this to get serial number
// Write new one and patch into tree.
// UpdateObjectHeader updates the header on NAND for an object.
// If name is not NULL, then that new name is used.
//
-int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int isShrink)
+int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int isShrink,int shadows)
{
yaffs_BlockInfo *bi;
// Header data
oh->type = in->variantType;
- oh->st_mode = in->st_mode;
+ oh->yst_mode = in->yst_mode;
+
+ // shadowing
+ oh->shadowsObject = shadows;
#ifdef CONFIG_YAFFS_WINCE
oh->win_atime[0] = in->win_atime[0];
oh->win_ctime[1] = in->win_ctime[1];
oh->win_mtime[1] = in->win_mtime[1];
#else
- oh->st_uid = in->st_uid;
- oh->st_gid = in->st_gid;
- oh->st_atime = in->st_atime;
- oh->st_mtime = in->st_mtime;
- oh->st_ctime = in->st_ctime;
- oh->st_rdev = in->st_rdev;
+ oh->yst_uid = in->yst_uid;
+ oh->yst_gid = in->yst_gid;
+ oh->yst_atime = in->yst_atime;
+ oh->yst_mtime = in->yst_mtime;
+ oh->yst_ctime = in->yst_ctime;
+ oh->yst_rdev = in->yst_rdev;
#endif
if(in->parent)
{
newTags.extraFileLength = oh->fileSize;
newTags.extraIsShrinkHeader = oh->isShrink;
newTags.extraEquivalentObjectId = oh->equivalentObjectId;
+ newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0;
newTags.extraObjectType = in->variantType;
// Create new chunk in NAND
static void yaffs_FlushFilesChunkCache(yaffs_Object *obj)
{
yaffs_Device *dev = obj->myDev;
- int lowest;
+ int lowest = -99; // Stop compiler whining.
int i;
yaffs_ChunkCache *cache;
int chunkWritten = 0;
if(cache && !cache->locked)
{
//Write it out and free it up
-
-#if 0
- nBytes = cache->object->variant.fileVariant.fileSize - ((cache->chunkId -1) * YAFFS_BYTES_PER_CHUNK);
- if(nBytes > YAFFS_BYTES_PER_CHUNK)
- {
- nBytes= YAFFS_BYTES_PER_CHUNK;
- }
-#endif
chunkWritten = yaffs_WriteChunkDataToObject(cache->object,
- cache->chunkId,
- cache->data,
- cache->nBytes,1);
-
+ cache->chunkId,
+ cache->data,
+ cache->nBytes,1);
cache->dirty = 0;
cache->object = NULL;
}
yaffs_ChunkCache *cache;
// If we can't find the data in the cache, then load it up.
cache = yaffs_FindChunkCache(in,chunk);
- if(!cache && yaffs_CheckSpaceForChunkCache(in->myDev))
+ if(!cache && yaffs_CheckSpaceForAllocation(in->myDev))
{
cache = yaffs_GrabChunkCache(in->myDev);
cache->object = in;
return yaffs_GetFileSize(in);
}
+ if(newSize == oldFileSize)
+ {
+ return oldFileSize;
+ }
+
if(newSize < oldFileSize)
{
in->variant.fileVariant.fileSize = newSize;
yaffs_PruneFileStructure(dev,&in->variant.fileVariant);
-
- // Write a new object header to show we've shrunk the file
- // Do this only if the file is not in the deleted directories.
- if(in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
- in->parent->objectId != YAFFS_OBJECTID_DELETED
- )
- {
- yaffs_UpdateObjectHeader(in,NULL, 0, 1);
- }
-
-
- return newSize;
-
}
- else
+
+ // Write a new object header.
+ // show we've shrunk the file, if need be
+ // Do this only if the file is not in the deleted directories.
+ if(in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
+ in->parent->objectId != YAFFS_OBJECTID_DELETED
+ )
{
- return oldFileSize;
+ yaffs_UpdateObjectHeader(in,NULL, 0, (newSize < oldFileSize) ? 1 : 0 ,0);
}
+
+
+ return newSize;
}
yfsd_WinFileTimeNow(in->win_mtime);
#else
- in->st_mtime = Y_CURRENT_TIME;
+ in->yst_mtime = Y_CURRENT_TIME;
#endif
}
- retVal = (yaffs_UpdateObjectHeader(in,NULL,0,0) >= 0)? YAFFS_OK : YAFFS_FAIL;
+ retVal = (yaffs_UpdateObjectHeader(in,NULL,0,0,0) >= 0)? YAFFS_OK : YAFFS_FAIL;
}
else
{
if(in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir))
{
// Move to the unlinked directory so we have a record that it was deleted.
- yaffs_ChangeObjectName(in, in->myDev->deletedDir,NULL,0);
+ yaffs_ChangeObjectName(in, in->myDev->deletedDir,NULL,0,0);
}
yaffs_RemoveObjectFromDirectory(in);
yaffs_DeleteChunk(in->myDev,in->chunkId,1,__LINE__);
in->chunkId = -1;
-#if 0
-#ifdef __KERNEL__
- if(in->myInode)
- {
- in->myInode->u.generic_ip = NULL;
- in->myInode = 0;
- }
-#endif
-#endif
yaffs_FreeObject(in);
return YAFFS_OK;
static int yaffs_UnlinkFile(yaffs_Object *in)
{
-#ifdef CONFIG_YAFFS_DISABLE_BACKGROUND_DELETION
- // Delete the file data & tnodes
-
- yaffs_DeleteWorker(in, in->variant.fileVariant.top, in->variant.fileVariant.topLevel, 0,NULL);
-
-
- yaffs_FreeTnode(in->myDev,in->variant.fileVariant.top);
-
- return yaffs_DoGenericObjectDeletion(in);
-#else
int retVal;
int immediateDeletion=0;
#endif
if(immediateDeletion)
{
- retVal = yaffs_ChangeObjectName(in, in->myDev->deletedDir,NULL,0);
+ retVal = yaffs_ChangeObjectName(in, in->myDev->deletedDir,NULL,0,0);
T(YAFFS_TRACE_TRACING,(TSTR("yaffs: immediate deletion of file %d" TENDSTR),in->objectId));
in->deleted=1;
in->myDev->nDeletedFiles++;
}
else
{
- retVal = yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,NULL,0);
+ retVal = yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,NULL,0,0);
}
}
return retVal;
-
-
-#endif
}
int yaffs_DeleteFile(yaffs_Object *in)
yaffs_GetObjectName(hl,name,YAFFS_MAX_NAME_LENGTH+1);
- retVal = yaffs_ChangeObjectName(obj, hl->parent, name,0);
+ retVal = yaffs_ChangeObjectName(obj, hl->parent, name,0,0);
if(retVal == YAFFS_OK)
{
//////////////// Initialisation Scanning /////////////////
-#if 0
-// For now we use the SmartMedia check.
-// We look at the blockStatus byte in the first two chunks
-// These must be 0xFF to pass as OK.
-// todo: this function needs to be modifyable foir different NAND types
-// and different chunk sizes. Suggest make this into a per-device configurable
-// function.
-static int yaffs_IsBlockBad(yaffs_Device *dev, int blk)
+static void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId, int backwardScanning)
{
- yaffsExtendedTags *tags;
+ yaffs_Object *obj;
- yaffs_ReadChunkFromNAND(dev,blk * dev->nChunksPerBlock,NULL,&tags,1);
-#if 1
- if(yaffs_CountBits(spare.blockStatus) < 7)
+ if(!backwardScanning)
{
- return 1;
- }
-#else
- if(spare.blockStatus != 0xFF)
- {
- return 1;
- }
-#endif
- yaffs_ReadChunkFromNAND(dev,blk * dev->nChunksPerBlock + 1,NULL,&spare,1);
-
-#if 1
- if(yaffs_CountBits(spare.blockStatus) < 7)
- {
- return 1;
+ // Handle YAFFS1 forward scanning case
+ // For YAFFS1 we always do the deletion
+
}
-#else
- if(spare.blockStatus != 0xFF)
- {
- return 1;
+ else
+ { // Handle YAFFS2 case (backward scanning)
+ // If the shadowed object exists then ignore.
+ if(yaffs_FindObjectByNumber(dev,objId))
+ {
+ return;
+ }
}
-#endif
- return 0;
+ // Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc.
+ // We put it in unlinked dir to be cleaned up after the scanning
+ obj = yaffs_FindOrCreateObjectByNumber(dev,objId,YAFFS_OBJECT_TYPE_FILE);
+ yaffs_AddObjectToDirectory(dev->unlinkedDir,obj);
+ obj->variant.fileVariant.shrinkSize = 0;
+ obj->valid = 1; // So that we don't read any other infor for this file
}
-#endif
+
typedef struct
in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,oh->type);
+ if(oh->shadowsObject > 0)
+ {
+ yaffs_HandleShadowedObject(dev,oh->shadowsObject,0);
+ }
+
if(in->valid)
{
// We have already filled this one. We have a duplicate and need to resolve it.
in->valid = 1;
in->variantType = oh->type;
- in->st_mode = oh->st_mode;
+ in->yst_mode = oh->yst_mode;
#ifdef CONFIG_YAFFS_WINCE
in->win_atime[0] = oh->win_atime[0];
in->win_ctime[0] = oh->win_ctime[0];
in->win_ctime[1] = oh->win_ctime[1];
in->win_mtime[1] = oh->win_mtime[1];
#else
- in->st_uid = oh->st_uid;
- in->st_gid = oh->st_gid;
- in->st_atime = oh->st_atime;
- in->st_mtime = oh->st_mtime;
- in->st_ctime = oh->st_ctime;
- in->st_rdev = oh->st_rdev;
+ in->yst_uid = oh->yst_uid;
+ in->yst_gid = oh->yst_gid;
+ in->yst_atime = oh->yst_atime;
+ in->yst_mtime = oh->yst_mtime;
+ in->yst_ctime = oh->yst_ctime;
+ in->yst_rdev = oh->yst_rdev;
#endif
in->chunkId = chunk;
in->valid = 1;
in->variantType = oh->type;
- in->st_mode = oh->st_mode;
+ in->yst_mode = oh->yst_mode;
#ifdef CONFIG_YAFFS_WINCE
in->win_atime[0] = oh->win_atime[0];
in->win_ctime[0] = oh->win_ctime[0];
in->win_ctime[1] = oh->win_ctime[1];
in->win_mtime[1] = oh->win_mtime[1];
#else
- in->st_uid = oh->st_uid;
- in->st_gid = oh->st_gid;
- in->st_atime = oh->st_atime;
- in->st_mtime = oh->st_mtime;
- in->st_ctime = oh->st_ctime;
- in->st_rdev = oh->st_rdev;
+ in->yst_uid = oh->yst_uid;
+ in->yst_gid = oh->yst_gid;
+ in->yst_atime = oh->yst_atime;
+ in->yst_mtime = oh->yst_mtime;
+ in->yst_ctime = oh->yst_ctime;
+ in->yst_rdev = oh->yst_rdev;
#endif
in->chunkId = chunk;
}
+ // Handle the unlinked files. Since they were left in an unlinked state we should
+ // just delete them.
{
struct list_head *i;
struct list_head *n;
dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
- if(dev->isYaffs2)
- {
- blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
- }
+ blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
// Scan all the blocks to determine their state
// Sort the blocks
// Dungy old bubble sort for now...
- if(dev->isYaffs2)
{
yaffs_BlockIndex temp;
int i;
// Now scan the blocks looking at the data.
- if(dev->isYaffs2)
- {
- startIterator = 0;
- endIterator = nBlocksToScan-1;
- T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("%d blocks to be scanned" TENDSTR),nBlocksToScan));
- }
+ startIterator = 0;
+ endIterator = nBlocksToScan-1;
+ T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("%d blocks to be scanned" TENDSTR),nBlocksToScan));
// For each block.... backwards
isShrink = 1;
}
- if(in->variant.fileVariant.shrinkSize > thisSize)
+ if(isShrink &&
+ in->variant.fileVariant.shrinkSize > thisSize)
{
in->variant.fileVariant.shrinkSize = thisSize;
}
in->valid = 1;
in->variantType = oh->type;
- in->st_mode = oh->st_mode;
+ in->yst_mode = oh->yst_mode;
#ifdef CONFIG_YAFFS_WINCE
in->win_atime[0] = oh->win_atime[0];
in->win_ctime[0] = oh->win_ctime[0];
in->win_ctime[1] = oh->win_ctime[1];
in->win_mtime[1] = oh->win_mtime[1];
#else
- in->st_uid = oh->st_uid;
- in->st_gid = oh->st_gid;
- in->st_atime = oh->st_atime;
- in->st_mtime = oh->st_mtime;
- in->st_ctime = oh->st_ctime;
- in->st_rdev = oh->st_rdev;
+ in->yst_uid = oh->yst_uid;
+ in->yst_gid = oh->yst_gid;
+ in->yst_atime = oh->yst_atime;
+ in->yst_mtime = oh->yst_mtime;
+ in->yst_ctime = oh->yst_ctime;
+ in->yst_rdev = oh->yst_rdev;
#endif
in->chunkId = chunk;
in->valid = 1;
in->variantType = oh->type;
- in->st_mode = oh->st_mode;
+ in->yst_mode = oh->yst_mode;
#ifdef CONFIG_YAFFS_WINCE
in->win_atime[0] = oh->win_atime[0];
in->win_ctime[0] = oh->win_ctime[0];
in->win_ctime[1] = oh->win_ctime[1];
in->win_mtime[1] = oh->win_mtime[1];
#else
- in->st_uid = oh->st_uid;
- in->st_gid = oh->st_gid;
- in->st_atime = oh->st_atime;
- in->st_mtime = oh->st_mtime;
- in->st_ctime = oh->st_ctime;
- in->st_rdev = oh->st_rdev;
+ in->yst_uid = oh->yst_uid;
+ in->yst_gid = oh->yst_gid;
+ in->yst_atime = oh->yst_atime;
+ in->yst_mtime = oh->yst_mtime;
+ in->yst_ctime = oh->yst_ctime;
+ in->yst_rdev = oh->yst_rdev;
#endif
in->chunkId = chunk;
+
+ if(oh->shadowsObject > 0)
+ {
+ yaffs_HandleShadowedObject(dev,oh->shadowsObject,1);
+ }
+
yaffs_SetObjectName(in,oh->name);
in->dirty = 0;
if(in->variant.fileVariant.scannedFileSize < oh->fileSize)
{
+ // This covers the case where the file size is > than where the data is
+ // This will happen if the file is resized to be larger than its current
+ // data extents.
in->variant.fileVariant.fileSize = oh->fileSize;
in->variant.fileVariant.scannedFileSize = in->variant.fileVariant.fileSize;
- }
-
-
+ }
- if(in->variant.fileVariant.shrinkSize > oh->fileSize)
+ if(oh->isShrink &&
+ in->variant.fileVariant.shrinkSize > oh->fileSize)
{
in->variant.fileVariant.shrinkSize = oh->fileSize;
- }
-
+ }
break;
case YAFFS_OBJECT_TYPE_HARDLINK:
break;
}
-#if 0
- if(parent == dev->deletedDir)
- {
- yaffs_DestroyObject(in);
- bi->hasShrinkHeader = 1;
- }
-#endif
- //T((" %d %d header %d \"%s\" type %d\n",blk,c,tags.objectId,oh->name,in->variantType));
+ //T((" %d %d header %d \"%s\" type %d\n",blk,c,tags.objectId,oh->name,in->variantType));
}
}
}
yaffs_Object *l;
+ if(!name)
+ {
+ return NULL;
+ }
if(!directory)
{
case YAFFS_OBJECT_TYPE_SYMLINK: return DT_LNK; break;
case YAFFS_OBJECT_TYPE_HARDLINK: return DT_REG; break;
case YAFFS_OBJECT_TYPE_SPECIAL:
- if(S_ISFIFO(obj->st_mode)) return DT_FIFO;
- if(S_ISCHR(obj->st_mode)) return DT_CHR;
- if(S_ISBLK(obj->st_mode)) return DT_BLK;
- if(S_ISSOCK(obj->st_mode)) return DT_SOCK;
+ if(S_ISFIFO(obj->yst_mode)) return DT_FIFO;
+ if(S_ISCHR(obj->yst_mode)) return DT_CHR;
+ if(S_ISBLK(obj->yst_mode)) return DT_BLK;
+ if(S_ISSOCK(obj->yst_mode)) return DT_SOCK;
default: return DT_REG; break;
}
}
{
unsigned int valid = attr->ia_valid;
- if(valid & ATTR_MODE) obj->st_mode = attr->ia_mode;
- if(valid & ATTR_UID) obj->st_uid = attr->ia_uid;
- if(valid & ATTR_GID) obj->st_gid = attr->ia_gid;
+ if(valid & ATTR_MODE) obj->yst_mode = attr->ia_mode;
+ if(valid & ATTR_UID) obj->yst_uid = attr->ia_uid;
+ if(valid & ATTR_GID) obj->yst_gid = attr->ia_gid;
- if(valid & ATTR_ATIME) obj->st_atime = Y_TIME_CONVERT(attr->ia_atime);
- if(valid & ATTR_CTIME) obj->st_ctime = Y_TIME_CONVERT(attr->ia_ctime);
- if(valid & ATTR_MTIME) obj->st_mtime = Y_TIME_CONVERT(attr->ia_mtime);
+ if(valid & ATTR_ATIME) obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
+ if(valid & ATTR_CTIME) obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime);
+ if(valid & ATTR_MTIME) obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
if(valid & ATTR_SIZE) yaffs_ResizeFile(obj,attr->ia_size);
- yaffs_UpdateObjectHeader(obj,NULL,1,0);
+ yaffs_UpdateObjectHeader(obj,NULL,1,0,0);
return YAFFS_OK;
{
unsigned int valid = 0;
- attr->ia_mode = obj->st_mode; valid |= ATTR_MODE;
- attr->ia_uid = obj->st_uid; valid |= ATTR_UID;
- attr->ia_gid = obj->st_gid; valid |= ATTR_GID;
+ attr->ia_mode = obj->yst_mode; valid |= ATTR_MODE;
+ attr->ia_uid = obj->yst_uid; valid |= ATTR_UID;
+ attr->ia_gid = obj->yst_gid; valid |= ATTR_GID;
- Y_TIME_CONVERT(attr->ia_atime)= obj->st_atime; valid |= ATTR_ATIME;
- Y_TIME_CONVERT(attr->ia_ctime) = obj->st_ctime; valid |= ATTR_CTIME;
- Y_TIME_CONVERT(attr->ia_mtime) = obj->st_mtime; valid |= ATTR_MTIME;
+ Y_TIME_CONVERT(attr->ia_atime)= obj->yst_atime; valid |= ATTR_ATIME;
+ Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime; valid |= ATTR_CTIME;
+ Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime; valid |= ATTR_MTIME;
attr->ia_size = yaffs_GetFileSize(obj); valid |= ATTR_SIZE;
obj->objectId,yaffs_GetObjectInode(obj), name, obj->dirty, obj->valid, obj->serial,
obj->sum, obj->chunkId, yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj)));
-#if 0
- YPRINTF(("Object %d \"%s\"\n dirty %d valid %d serial %d sum %d chunk %d\n",
- obj->objectId, oh->name, obj->dirty, obj->valid, obj->serial,
- obj->sum, obj->chunkId));
- switch(obj->variantType)
- {
- case YAFFS_OBJECT_TYPE_FILE:
- YPRINTF((" FILE length %d\n",obj->variant.fileVariant.fileSize));
- break;
- case YAFFS_OBJECT_TYPE_DIRECTORY:
- YPRINTF((" DIRECTORY\n"));
- break;
- case YAFFS_OBJECT_TYPE_HARDLINK: //todo
- case YAFFS_OBJECT_TYPE_SYMLINK:
- case YAFFS_OBJECT_TYPE_UNKNOWN:
- default:
- }
-#endif
+
return YAFFS_OK;
}
///////////////////////// Initialisation code ///////////////////////////
-int yaffs_CheckDevFunctions(const yaffs_Device *dev)
+static int yaffs_CheckDevFunctions(const yaffs_Device *dev)
{
// Common functions, gotta have
dev->internalEndBlock = dev->endBlock;
dev->blockOffset = 0;
dev->chunkOffset = 0;
+ dev->nFreeChunks = 0;
if(dev->startBlock == 0)
{
dev->tagsEccUnfixed=0;
dev->nErasureFailures = 0;
dev->nErasedBlocks = 0;
+ dev->isDoingGC = 0;
//dev->localBuffer = YMALLOC(dev->nBytesPerChunk);
// Initialise temporary buffers
// Zero out stats
dev->nPageReads = 0;
- dev->nPageWrites = 0;
+ dev->nPageWrites = 0;
dev->nBlockErasures = 0;
dev->nGCCopies = 0;
dev->nRetriedWrites = 0;
dev->nRetiredBlocks = 0;
+
+ yaffs_VerifyFreeChunks(dev);
T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));
return YAFFS_OK;
}
-#if 0
-int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
-{
- int nFree = dev->nFreeChunks - (dev->nChunksPerBlock * YAFFS_RESERVED_BLOCKS);
-
- struct list_head *i;
- yaffs_Object *l;
-
-
- // To the free chunks add the chunks that are in the deleted unlinked files.
- list_for_each(i,&dev->deletedDir->variant.directoryVariant.children)
- {
- l = list_entry(i, yaffs_Object,siblings);
- if(l->deleted)
- {
- nFree++;
- nFree += l->nDataChunks;
- }
- }
-
-
- // printf("___________ nFreeChunks is %d nFree is %d\n",dev->nFreeChunks,nFree);
-
- if(nFree < 0) nFree = 0;
-
- return nFree;
-
-}
-
-#endif
-
-int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
+static int yaffs_CountFreeChunks(yaffs_Device *dev)
{
int nFree;
- int pending;
int b;
- int nDirtyCacheChunks=0;
-
- yaffs_BlockInfo *blk;
-
- struct list_head *i;
- yaffs_Object *l;
+
+ yaffs_BlockInfo *blk;
+
for(nFree = 0, b = dev->internalStartBlock; b <= dev->internalEndBlock; b++)
{
{
case YAFFS_BLOCK_STATE_EMPTY:
case YAFFS_BLOCK_STATE_ALLOCATING:
- case YAFFS_BLOCK_STATE_FULL: nFree += (dev->nChunksPerBlock - blk->pagesInUse); break;
+ case YAFFS_BLOCK_STATE_COLLECTING:
+ case YAFFS_BLOCK_STATE_FULL: nFree += (dev->nChunksPerBlock - blk->pagesInUse + blk->softDeletions); break;
default: break;
}
+
}
+ return nFree;
+}
- pending = 0;
-
- // To the free chunks add the chunks that are in the deleted unlinked files.
- list_for_each(i,&dev->deletedDir->variant.directoryVariant.children)
- {
- if(i)
- {
- l = list_entry(i, yaffs_Object,siblings);
- if(l->deleted)
- {
- pending++;
- pending += l->nDataChunks;
- }
- }
- }
-
-
-
- //printf("___________ really free is %d, pending %d, nFree is %d\n",nFree,pending, nFree+pending);
-
- if(nFree != dev->nFreeChunks)
- {
- // printf("___________Different! really free is %d, nFreeChunks %d\n",nFree dev->nFreeChunks);
- }
- nFree += pending;
+
+int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
+{
+ // This is what we report to the outside world
+
+ int nFree;
+ int nDirtyCacheChunks;
+
+#if 1
+ nFree = dev->nFreeChunks;
+#else
+ nFree = yaffs_CountFreeChunks(dev);
+#endif
// Now count the number of dirty chunks in the cache and subtract those
{
int i;
- for(i = 0; i < dev->nShortOpCaches; i++)
+ for( nDirtyCacheChunks = 0,i = 0; i < dev->nShortOpCaches; i++)
{
if(dev->srCache[i].dirty) nDirtyCacheChunks++;
}
}
+static int yaffs_freeVerificationFailures;
+static void yaffs_VerifyFreeChunks(yaffs_Device *dev)
+{
+ int counted = yaffs_CountFreeChunks(dev);
+
+ int difference = dev->nFreeChunks - counted;
+
+ if(difference)
+ {
+ T(YAFFS_TRACE_ALWAYS,(TSTR("Freechunks verification failure %d %d %d" TENDSTR),dev->nFreeChunks,counted,difference));
+ yaffs_freeVerificationFailures++;
+ }
+}
/////////////////// YAFFS test code //////////////////////////////////
return YAFFS_OK;
}
-#if 0
-void yaffs_GutsTest(yaffs_Device *dev)
-{
-
- if(yaffs_CheckStructures() != YAFFS_OK)
- {
- T(YAFFS_TRACE_ALWAYS,(TSTR("One or more structures malformed-- aborting\n" TENDSTR)));
- return;
- }
-
- yaffs_TnodeTest(dev);
- yaffs_ObjectTest(dev);
-}
-#endif
+