*/
//yaffs_guts.c
-const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.16 2003-01-14 23:15:29 charles Exp $";
+const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.35 2004-09-21 03:03:12 charles Exp $";
#include "yportenv.h"
#include "yaffsinterface.h"
#include "yaffs_guts.h"
+#define YAFFS_PASSIVE_GC_CHUNKS 2
-#define YAFFS_GARBAGE_COLLECT_LOW_WATER 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
// 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 int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare)
{
- if(chunkInNAND < dev->startBlock * YAFFS_CHUNKS_PER_BLOCK)
+ if(chunkInNAND < dev->startBlock * dev->nChunksPerBlock)
{
T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs chunk %d is not valid" TENDSTR),chunkInNAND));
return YAFFS_FAIL;
int retVal;
yaffs_Spare localSpare;
- __u8 calcEcc[3];
- int eccResult1,eccResult2;
- struct yaffs_NANDSpare nspare;
-
dev->nPageReads++;
{
// Do ECC correction
//Todo handle any errors
- nand_calculate_ecc(data,calcEcc);
- eccResult1 = nand_correct_data (data,spare->ecc1, calcEcc);
- nand_calculate_ecc(&data[256],calcEcc);
- eccResult2 = nand_correct_data (&data[256],spare->ecc2, calcEcc);
+ int eccResult1,eccResult2;
+ __u8 calcEcc[3];
+
+ yaffs_ECCCalculate(data,calcEcc);
+ eccResult1 = yaffs_ECCCorrect (data,spare->ecc1, calcEcc);
+ yaffs_ECCCalculate(&data[256],calcEcc);
+ eccResult2 = yaffs_ECCCorrect(&data[256],spare->ecc2, calcEcc);
if(eccResult1>0)
{
}
else
{
+ // Must allocate enough memory for spare+2*sizeof(int) for ecc results from device.
+ struct yaffs_NANDSpare nspare;
retVal = dev->readChunkFromNAND(dev,chunkInNAND,data,(yaffs_Spare*)&nspare);
memcpy (spare, &nspare, sizeof(yaffs_Spare));
if(data && doErrorCorrection)
T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND));
}
- if(nspare.eccres2 || nspare.eccres2)
+ if(nspare.eccres1 || nspare.eccres2)
{
// Hoosterman, we had a data problem on this page
yaffs_HandleReadDataError(dev,chunkInNAND);
static int init = 0;
static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
static __u8 data[YAFFS_BYTES_PER_CHUNK];
- static __u8 spare[16];
-
-
- dev->readChunkFromNAND(dev,chunkInNAND,data,(yaffs_Spare *)spare);
-
-
+ // Might as well always allocate the larger size for dev->useNANDECC == true;
+ static __u8 spare[sizeof(struct yaffs_NANDSpare)];
+
+ dev->readChunkFromNAND(dev,chunkInNAND,data,(yaffs_Spare *)spare);
if(!init)
{
spare.blockStatus = 0;
- yaffs_WriteChunkToNAND(dev, blockInNAND * YAFFS_CHUNKS_PER_BLOCK, NULL , &spare);
- yaffs_WriteChunkToNAND(dev, blockInNAND * YAFFS_CHUNKS_PER_BLOCK + 1, NULL , &spare);
+ // TODO change this retirement marking for other NAND types
+ yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL , &spare);
+ yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1, NULL , &spare);
yaffs_GetBlockInfo(dev,blockInNAND)->blockState = YAFFS_BLOCK_STATE_DEAD;
dev->nRetiredBlocks++;
static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND)
{
- int blockInNAND = chunkInNAND/YAFFS_CHUNKS_PER_BLOCK;
+ int blockInNAND = chunkInNAND/dev->nChunksPerBlock;
// Mark the block for retirement
yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1;
static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND)
{
- int blockInNAND = chunkInNAND/YAFFS_CHUNKS_PER_BLOCK;
+ int blockInNAND = chunkInNAND/dev->nChunksPerBlock;
// Mark the block for retirement
yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1;
void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare)
{
- nand_calculate_ecc (data , spare->ecc1);
- nand_calculate_ecc (&data[256] , spare->ecc2);
+ yaffs_ECCCalculate(data , spare->ecc1);
+ yaffs_ECCCalculate(&data[256] , spare->ecc2);
}
void yaffs_CalcTagsECC(yaffs_Tags *tags)
static void yaffs_DeinitialiseTnodes(yaffs_Device*dev)
{
// Free the list of allocated tnodes
-
+ yaffs_TnodeList *tmp;
+
while(dev->allocatedTnodeList)
{
+ tmp = dev->allocatedTnodeList->next;
+
YFREE(dev->allocatedTnodeList->tnodes);
- dev->allocatedTnodeList = dev->allocatedTnodeList->next;
+ YFREE(dev->allocatedTnodeList);
+ dev->allocatedTnodeList = tmp;
+
}
dev->freeTnodes = NULL;
if(limit)
{
*limit = *limit-1;
- if(limit <= 0)
+ if(*limit <= 0)
{
hitLimit = 1;
}
{
if(tn->level0[i])
{
-
+ // Note this does not find the real chunk, only the chunk group.
+ // We make an assumption that a chunk group is niot larger than a block.
theChunk = (tn->level0[i] << in->myDev->chunkGroupBits);
- theBlock = yaffs_GetBlockInfo(in->myDev, theChunk/ YAFFS_CHUNKS_PER_BLOCK);
+ T(YAFFS_TRACE_SCAN,(TSTR("soft delete tch %d cgb %d chunk %d" TENDSTR),
+ tn->level0[i],in->myDev->chunkGroupBits,theChunk));
+
+ theBlock = yaffs_GetBlockInfo(in->myDev, theChunk/in->myDev->nChunksPerBlock);
if(theBlock)
{
theBlock->softDeletions++;
{
// Free the list of allocated Objects
+ yaffs_ObjectList *tmp;
+
while( dev->allocatedObjectList)
{
+ tmp = dev->allocatedObjectList->next;
YFREE(dev->allocatedObjectList->objects);
- dev->allocatedObjectList = dev->allocatedObjectList->next;
+ YFREE(dev->allocatedObjectList);
+
+ dev->allocatedObjectList = tmp;
}
dev->freeObjects = NULL;
list_for_each(i,&dev->objectBucket[bucket].list)
{
// If there is already one in the list
- if(list_entry(i, yaffs_Object,hashLink)->objectId == n)
+ if(i && list_entry(i, yaffs_Object,hashLink)->objectId == n)
{
found = 0;
}
list_for_each(i,&dev->objectBucket[bucket].list)
{
// Look if it is in the list
- in = list_entry(i, yaffs_Object,hashLink);
- if(in->objectId == number)
+ if(i)
{
- return in;
+ in = list_entry(i, yaffs_Object,hashLink);
+ if(in->objectId == number)
+ {
+ return in;
+ }
}
}
theObject->win_ctime[1] = theObject->win_mtime[1] = theObject->win_atime[1];
#else
- theObject->st_atime = theObject->st_mtime = theObject->st_ctime = CURRENT_TIME;
+
+//#if defined(CONFIG_KERNEL_2_5)
+#if defined(__KERNEL__) && (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+ theObject->st_atime = theObject->st_mtime = theObject->st_ctime = CURRENT_TIME.tv_sec;
+#else
+ theObject->st_atime = theObject->st_mtime = theObject->st_ctime = CURRENT_TIME;
+#endif
#endif
switch(type)
{
#ifdef CONFIG_YAFFS_WINCE
yfsd_WinFileTimeNow(in->win_atime);
in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];
- in->win_ctime[1] = in->win_mtime[1] = in->win_atime[0];
+ in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
+#else
+//#if defined(CONFIG_KERNEL_2_5)
+#if defined(__KERNEL__) && (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+ in->st_atime = in->st_mtime = in->st_ctime = CURRENT_TIME.tv_sec;
#else
in->st_atime = in->st_mtime = in->st_ctime = CURRENT_TIME;
+#endif
in->st_rdev = rdev;
in->st_uid = uid;
in->st_gid = gid;
yaffs_Object *obj;
int force = 0;
-#ifdef YAFFS_CASE_INSENSITIVE
+#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
// Special case for WinCE.
// While look-up is case insensitive, the name isn't.
// THerefore we might want to change x.txt to X.txt
// FindDiretiestBlock is used to select the dirtiest block (or close enough)
// for garbage collection.
-static int yaffs_FindDirtiestBlock(yaffs_Device *dev)
+static int yaffs_FindDirtiestBlock(yaffs_Device *dev,int aggressive)
{
int b = dev->currentDirtyChecker;
int i;
+ int iterations;
int dirtiest = -1;
- int pagesInUse = dev->nChunksPerBlock;
+ int pagesInUse;
yaffs_BlockInfo *bi;
+
+ // If we're doing aggressive GC then we are happy to take a less-dirty block, and
+ // search further.
+
+ pagesInUse = (aggressive)? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1;
+ if(aggressive)
+ {
+ iterations = dev->endBlock - dev->startBlock + 1;
+ }
+ else
+ {
+ iterations = dev->endBlock - dev->startBlock + 1;
+ iterations = iterations / 16;
+ if(iterations > 200)
+ {
+ iterations = 200;
+ }
+ }
- for(i = dev->startBlock; i <= dev->endBlock && pagesInUse > 2 ; i++)
+ for(i = 0; i <= iterations && pagesInUse > 0 ; i++)
{
b++;
if ( b < dev->startBlock || b > dev->endBlock)
dev->allocationPage = 0;
}
- if(!useReserve && dev->nErasedBlocks <= YAFFS_RESERVED_BLOCKS)
+ if(!useReserve && dev->nErasedBlocks <= dev->nReservedBlocks)
{
// Not enough space to allocate unless we're allowed to use the reserve.
return -1;
{
bi = yaffs_GetBlockInfo(dev,dev->allocationBlock);
- retVal = (dev->allocationBlock * YAFFS_CHUNKS_PER_BLOCK) +
+ retVal = (dev->allocationBlock * dev->nChunksPerBlock) +
dev->allocationPage;
bi->pagesInUse++;
yaffs_SetChunkBit(dev,dev->allocationBlock,dev->allocationPage);
dev->nFreeChunks--;
// If the block is full set the state to full
- if(dev->allocationPage >= YAFFS_CHUNKS_PER_BLOCK)
+ if(dev->allocationPage >= dev->nChunksPerBlock)
{
bi->blockState = YAFFS_BLOCK_STATE_FULL;
dev->allocationBlock = -1;
// number of erased blocks.
// The cache is allowed to use reserved blocks.
-int yaffs_CheckSpaceForChunkCache(yaffs_Device *dev)
+static int yaffs_CheckSpaceForChunkCache(yaffs_Device *dev)
{
- return (dev->nErasedBlocks >= YAFFS_RESERVED_BLOCKS);
+ return (dev->nErasedBlocks >= dev->nReservedBlocks);
}
-int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
+static int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
{
int oldChunk;
int newChunk;
yaffs_Spare spare;
yaffs_Tags tags;
- __u8 buffer[YAFFS_BYTES_PER_CHUNK];
+ __u8 buffer[YAFFS_BYTES_PER_CHUNK];
// yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,block);
//T(("Collecting block %d n %d bits %x\n",block, bi->pagesInUse, bi->pageBits));
- for(chunkInBlock = 0,oldChunk = block * YAFFS_CHUNKS_PER_BLOCK;
+ for(chunkInBlock = 0,oldChunk = block * dev->nChunksPerBlock;
chunkInBlock < dev->nChunksPerBlock && yaffs_StillSomeChunkBits(dev,block);
chunkInBlock++, oldChunk++ )
{
{
// It's a header
object->chunkId = newChunk;
+ object->serial = tags.serialNumber;
}
else
{
//Scan the unlinked files looking for one to delete
list_for_each(i,&dev->unlinkedDir->variant.directoryVariant.children)
{
- l = list_entry(i, yaffs_Object,siblings);
- if(l->deleted)
+ if(i)
{
- return l;
+ l = list_entry(i, yaffs_Object,siblings);
+ if(l->deleted)
+ {
+ return l;
+ }
}
}
return NULL;
}
-
+#if 0
+#define YAFFS_GARBAGE_COLLECT_LOW_WATER 2
static int yaffs_CheckGarbageCollection(yaffs_Device *dev)
{
int block;
+ int aggressive=0;
//yaffs_DoUnlinkedFileDeletion(dev);
- if(dev->nErasedBlocks <= (YAFFS_RESERVED_BLOCKS + YAFFS_GARBAGE_COLLECT_LOW_WATER))
+ if(dev->nErasedBlocks <= (dev->nReservedBlocks + YAFFS_GARBAGE_COLLECT_LOW_WATER))
{
- dev->garbageCollectionRequired = 1;
- }
+ aggressive = 1;
+ }
- if(dev->garbageCollectionRequired)
+ if(aggressive)
{
- dev->garbageCollections++;
- dev->garbageCollectionRequired = 0;
- if(dev->blockSelectedForGC >= 0)
- {
- block = dev->blockSelectedForGC;
- }
- else
- {
- block = yaffs_FindDirtiestBlock(dev);
- }
+ block = yaffs_FindDirtiestBlock(dev,aggressive);
if(block >= 0)
{
+ dev->garbageCollections++;
return yaffs_GarbageCollectBlock(dev,block);
}
else
return YAFFS_OK;
}
+#endif
+
+// New garbage collector
+// If we're very low on erased blocks then we do aggressive garbage collection
+// otherwise we do "passive" garbage collection.
+// Aggressive gc looks further (whole array) and will accept dirtier blocks.
+// Passive gc only inspects smaller areas and will only accept cleaner blocks.
+//
+// The idea is to help clear out space in a more spread-out manner.
+// Dunno if it really does anything useful.
+//
+static int yaffs_CheckGarbageCollection(yaffs_Device *dev)
+{
+ int block;
+ int aggressive=0;
+
+ //yaffs_DoUnlinkedFileDeletion(dev);
+
+ if(dev->nErasedBlocks <= (dev->nReservedBlocks + 1))
+ {
+ aggressive = 1;
+ }
+
+ block = yaffs_FindDirtiestBlock(dev,aggressive);
+
+ if(block >= 0)
+ {
+ dev->garbageCollections++;
+ if(!aggressive)
+ {
+ dev->passiveGarbageCollections++;
+ }
+
+ T(YAFFS_TRACE_GC,(TSTR("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),dev->nErasedBlocks,aggressive));
+
+ return yaffs_GarbageCollectBlock(dev,block);
+ }
+
+ return aggressive ? YAFFS_FAIL : YAFFS_OK;
+}
//////////////////////////// TAGS ///////////////////////////////////////
objId = in->objectId;
fSize = in->variant.fileVariant.fileSize;
- nChunks = (fSize + YAFFS_BYTES_PER_CHUNK -1)/YAFFS_BYTES_PER_CHUNK;
+ nChunks = (fSize + in->myDev->nBytesPerChunk -1)/in->myDev->nBytesPerChunk;
for(chunk = 1; chunk <= nChunks; chunk++)
{
}
else
{
+ memset(buffer,0,YAFFS_BYTES_PER_CHUNK);
return 0;
}
if(chunkId <= 0) return;
dev->nDeletions++;
- block = chunkId / YAFFS_CHUNKS_PER_BLOCK;
- page = chunkId % YAFFS_CHUNKS_PER_BLOCK;
+ block = chunkId / dev->nChunksPerBlock;
+ page = chunkId % dev->nChunksPerBlock;
if(markNAND)
{
yaffs_SpareInitialise(&spare);
-
+
+#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
+
+ //read data before write, to ensure correct ecc
+ //if we're using MTD verification under Linux
+ yaffs_ReadChunkFromNAND(dev,chunkId,NULL,&spare,0);
+#endif
+
spare.pageStatus = 0; // To mark it as deleted.
cache->nBytes,1);
cache->dirty = 0;
+ cache->object = NULL;
}
} while(cache && chunkWritten > 0);
if(!dev->srCache[i].object)
{
//T(("Grabbing empty %d\n",i));
+
+ //printf("Grabbing empty %d\n",i);
return &dev->srCache[i];
}
}
+
+ return NULL;
theOne = -1;
usage = 0; // just to stop the compiler grizzling
}
//T(("Grabbing non-empty %d\n",theOne));
+
+ //if(theOne >= 0) printf("Grabbed non-empty cache %d\n",theOne);
+
return theOne >= 0 ? &dev->srCache[theOne] : NULL;
}
else
yaffs_Object *theObj;
int usage;
int i;
+ int pushout;
if(dev->nShortOpCaches > 0)
{
theObj = dev->srCache[0].object;
usage = dev->srCache[0].lastUse;
+ cache = &dev->srCache[0];
+ pushout = 0;
for(i = 1; i < dev->nShortOpCaches; i++)
{
{
usage = dev->srCache[i].lastUse;
theObj = dev->srCache[i].object;
+ cache = &dev->srCache[i];
+ pushout = i;
}
}
- yaffs_FlushFilesChunkCache(theObj);
+ if(!cache || cache->dirty)
+ {
+
+ //printf("Dirty ");
+ yaffs_FlushFilesChunkCache(theObj);
- // Try again
- cache = yaffs_GrabChunkCacheWorker(dev);
+ // Try again
+ cache = yaffs_GrabChunkCacheWorker(dev);
+ }
+ else
+ {
+ //printf(" pushout %d\n",pushout);
+ }
+
}
-
+
return cache;
}
else
int nToCopy;
int n = nBytes;
int nDone = 0;
+ yaffs_ChunkCache *cache;
yaffs_Device *dev;
nToCopy = YAFFS_BYTES_PER_CHUNK - start;
}
- if(nToCopy != YAFFS_BYTES_PER_CHUNK)
+ cache = yaffs_FindChunkCache(in,chunk);
+
+ // If the chunk is already in the cache or it is less than a whole chunk
+ // then use the cache (if there is caching)
+ // else bypass the cache.
+ if( cache || nToCopy != YAFFS_BYTES_PER_CHUNK)
{
- // An incomplete start or end chunk (or maybe both start and end chunk)
if(dev->nShortOpCaches > 0)
{
- yaffs_ChunkCache *cache;
+
// If we can't find the data in the cache, then load it up.
- cache = yaffs_FindChunkCache(in,chunk);
+
if(!cache)
{
cache = yaffs_GrabChunkCache(in->myDev);
// using yaffs_DeleteChunk
chunkId = yaffs_FindAndDeleteChunkInFile(in,i,NULL);
- if(chunkId <= 0 || chunkId >= (dev->endBlock * 32))
+ if(chunkId < (dev->startBlock * 32) || chunkId >= ((dev->endBlock+1) * 32))
{
//T(("Found daft chunkId %d for %d\n",chunkId,i));
}
int lastChunk = 1+ newSize/YAFFS_BYTES_PER_CHUNK;
// Got to read and rewrite the last chunk with its new size.
+ // NB Got to zero pad to nuke old data
yaffs_ReadChunkDataFromObject(in,lastChunk,dev->localBuffer);
-
+ memset(dev->localBuffer + sizeOfPartialChunk,0, YAFFS_BYTES_PER_CHUNK - sizeOfPartialChunk);
+
yaffs_WriteChunkDataToObject(in,lastChunk,dev->localBuffer,sizeOfPartialChunk,1);
}
{
#ifdef CONFIG_YAFFS_WINCE
yfsd_WinFileTimeNow(in->win_mtime);
+#else
+//#if defined(CONFIG_KERNEL_2_5)
+#if defined(__KERNEL__) && (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+ in->st_mtime = CURRENT_TIME.tv_sec;
#else
in->st_mtime = CURRENT_TIME;
+#endif
#endif
}
- retVal = yaffs_UpdateObjectHeader(in,NULL,0);
+ retVal = (yaffs_UpdateObjectHeader(in,NULL,0) >= 0)? YAFFS_OK : YAFFS_FAIL;
}
else
{
{
yaffs_Spare spare;
- yaffs_ReadChunkFromNAND(dev,blk * YAFFS_CHUNKS_PER_BLOCK,NULL,&spare,1);
+ yaffs_ReadChunkFromNAND(dev,blk * dev->nChunksPerBlock,NULL,&spare,1);
#if 1
if(yaffs_CountBits(spare.blockStatus) < 7)
{
return 1;
}
#endif
- yaffs_ReadChunkFromNAND(dev,blk * YAFFS_CHUNKS_PER_BLOCK + 1,NULL,&spare,1);
+ yaffs_ReadChunkFromNAND(dev,blk * dev->nChunksPerBlock + 1,NULL,&spare,1);
#if 1
if(yaffs_CountBits(spare.blockStatus) < 7)
// Read each chunk in the block.
- for(c = 0; c < YAFFS_CHUNKS_PER_BLOCK &&
+ for(c = 0; c < dev->nChunksPerBlock &&
state == YAFFS_BLOCK_STATE_SCANNING; c++)
{
// Read the spare area and decide what to do
- chunk = blk * YAFFS_CHUNKS_PER_BLOCK + c;
+ chunk = blk * dev->nChunksPerBlock + c;
yaffs_ReadChunkFromNAND(dev,chunk,NULL,&spare,1);
dev->allocationPage = c;
}
- dev->nFreeChunks += (YAFFS_CHUNKS_PER_BLOCK - c);
+ dev->nFreeChunks += (dev->nChunksPerBlock - c);
}
else if(tags.chunkId > 0)
{
{
// Hoosterman, another problem....
// We're trying to use a non-directory as a directory
- // Todo ... handle
- T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: attempting to use non-directory as a directory in scan" TENDSTR)));
+
+ T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." TENDSTR)));
+ parent = dev->lostNFoundDir;
}
{
struct list_head *i;
+ struct list_head *n;
+
yaffs_Object *l;
// Soft delete all the unlinked files
- list_for_each(i,&dev->unlinkedDir->variant.directoryVariant.children)
+ list_for_each_safe(i,n,&dev->unlinkedDir->variant.directoryVariant.children)
{
- l = list_entry(i, yaffs_Object,siblings);
- if(l->deleted)
+ if(i)
{
- yaffs_SoftDeleteFile(l);
+ l = list_entry(i, yaffs_Object,siblings);
+ if(l->deleted)
+ {
+ yaffs_SoftDeleteFile(l);
+ }
}
}
}
list_for_each(i,&directory->variant.directoryVariant.children)
{
- l = list_entry(i, yaffs_Object,siblings);
-
- // Special case for lost-n-found
- if(l->objectId == YAFFS_OBJECTID_LOSTNFOUND)
+ if(i)
{
- if(yaffs_strcmp(name,YAFFS_LOSTNFOUND_NAME) == 0)
+ l = list_entry(i, yaffs_Object,siblings);
+
+ // Special case for lost-n-found
+ if(l->objectId == YAFFS_OBJECTID_LOSTNFOUND)
{
- return l;
+ if(yaffs_strcmp(name,YAFFS_LOSTNFOUND_NAME) == 0)
+ {
+ return l;
+ }
}
- }
- else if(yaffs_SumCompare(l->sum, sum))
- {
- // Do a real check
- yaffs_GetObjectName(l,buffer,YAFFS_MAX_NAME_LENGTH);
- if(yaffs_strcmp(name,buffer) == 0)
+ else if(yaffs_SumCompare(l->sum, sum))
{
- return l;
- }
-
+ // Do a real check
+ yaffs_GetObjectName(l,buffer,YAFFS_MAX_NAME_LENGTH);
+ if(yaffs_strcmp(name,buffer) == 0)
+ {
+ return l;
+ }
+ }
}
}
list_for_each(i,&theDir->variant.directoryVariant.children)
{
- l = list_entry(i, yaffs_Object,siblings);
- if(!fn(l))
+ if(i)
{
- return YAFFS_FAIL;
+ l = list_entry(i, yaffs_Object,siblings);
+ if(l && !fn(l))
+ {
+ return YAFFS_FAIL;
+ }
}
}
if(valid & ATTR_UID) obj->st_uid = attr->ia_uid;
if(valid & ATTR_GID) obj->st_gid = attr->ia_gid;
+//#if defined(CONFIG_KERNEL_2_5)
+#if defined(__KERNEL__) && (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+
+ if(valid & ATTR_ATIME) obj->st_atime = attr->ia_atime.tv_sec;
+ if(valid & ATTR_CTIME) obj->st_ctime = attr->ia_ctime.tv_sec;
+ if(valid & ATTR_MTIME) obj->st_mtime = attr->ia_mtime.tv_sec;
+#else
if(valid & ATTR_ATIME) obj->st_atime = attr->ia_atime;
if(valid & ATTR_CTIME) obj->st_ctime = attr->ia_ctime;
if(valid & ATTR_MTIME) obj->st_mtime = attr->ia_mtime;
+#endif
if(valid & ATTR_SIZE) yaffs_ResizeFile(obj,attr->ia_size);
attr->ia_uid = obj->st_uid; valid |= ATTR_UID;
attr->ia_gid = obj->st_gid; valid |= ATTR_GID;
+//#if defined(CONFIG_KERNEL_2_5)
+#if defined(__KERNEL__) && (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+ attr->ia_atime.tv_sec = obj->st_atime; valid |= ATTR_ATIME;
+ attr->ia_ctime.tv_sec = obj->st_ctime; valid |= ATTR_CTIME;
+ attr->ia_mtime.tv_sec = obj->st_mtime; valid |= ATTR_MTIME;
+#else
attr->ia_atime = obj->st_atime; valid |= ATTR_ATIME;
attr->ia_ctime = obj->st_ctime; valid |= ATTR_CTIME;
attr->ia_mtime = obj->st_mtime; valid |= ATTR_MTIME;
-
+#endif
attr->ia_size = yaffs_GetFileSize(obj); valid |= ATTR_SIZE;
attr->ia_valid = valid;
int extraBits;
int nBlocks;
+ if( dev->nBytesPerChunk != YAFFS_BYTES_PER_CHUNK ||
+ dev->nChunksPerBlock < 2 ||
+ dev->nReservedBlocks < 2 ||
+ dev->startBlock <= 0 ||
+ dev->endBlock <= 0 ||
+ dev->endBlock <= (dev->startBlock + dev->nReservedBlocks)
+ )
+ {
+ //these parameters must be set before stating yaffs
+ // Other parameters startBlock,
+ return YAFFS_FAIL;
+ }
+
if(!yaffs_CheckStructures())
// Calculate chunkGroupBits.
// We need to find the next power of 2 > than endBlock
- x = YAFFS_CHUNKS_PER_BLOCK * (dev->endBlock+1);
+ x = dev->nChunksPerBlock * (dev->endBlock+1);
for(bits = extraBits = 0; x > 1; bits++)
{
{
dev->chunkGroupBits = bits - 16;
}
+
dev->chunkGroupSize = 1 << dev->chunkGroupBits;
+
+ if(dev->nChunksPerBlock < dev->chunkGroupSize)
+ {
+ // We have a problem because the soft delete won't work if
+ // the chunk group size > chunks per block.
+ // This can be remedied by using larger "virtual blocks".
+
+ return YAFFS_FAIL;
+ }
+
- // Stuff to be taken out later
- dev->nBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
- dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
// More device initialisation
- dev->garbageCollectionRequired = 0;
dev->garbageCollections = 0;
+ dev->passiveGarbageCollections = 0;
dev->currentDirtyChecker = 0;
dev->bufferedBlock = -1;
dev->doingBufferedBlockRewrite = 0;
- dev->blockSelectedForGC = -1;
dev->nDeletedFiles = 0;
dev->nBackgroundDeletions=0;
dev->nUnlinkedFiles = 0;
yaffs_DeinitialiseBlocks(dev);
yaffs_DeinitialiseTnodes(dev);
yaffs_DeinitialiseObjects(dev);
+ if(dev->nShortOpCaches > 0)
+ YFREE(dev->srCache);
+ YFREE(dev->localBuffer);
}
}
int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
{
- int nFree = dev->nFreeChunks - (YAFFS_CHUNKS_PER_BLOCK * YAFFS_RESERVED_BLOCKS);
+ int nFree = dev->nFreeChunks - (dev->nChunksPerBlock * YAFFS_RESERVED_BLOCKS);
struct list_head *i;
yaffs_Object *l;
}
- printf("___________ nFreeChunks is %d nFree is %d\n",dev->nFreeChunks,nFree);
+ // printf("___________ nFreeChunks is %d nFree is %d\n",dev->nFreeChunks,nFree);
if(nFree < 0) nFree = 0;
int nFree;
int pending;
int b;
+ int nDirtyCacheChunks=0;
yaffs_BlockInfo *blk;
// To the free chunks add the chunks that are in the deleted unlinked files.
list_for_each(i,&dev->unlinkedDir->variant.directoryVariant.children)
{
- l = list_entry(i, yaffs_Object,siblings);
- if(l->deleted)
+ if(i)
{
- pending++;
- pending += l->nDataChunks;
+ l = list_entry(i, yaffs_Object,siblings);
+ if(l->deleted)
+ {
+ pending++;
+ pending += l->nDataChunks;
+ }
}
}
nFree += pending;
+ // Now count the number of dirty chunks in the cache and subtract those
+
+ {
+ int i;
+ for(i = 0; i < dev->nShortOpCaches; i++)
+ {
+ if(dev->srCache[i].dirty) nDirtyCacheChunks++;
+ }
+ }
+
+ nFree -= nDirtyCacheChunks;
+
+ nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock);
+
if(nFree < 0) nFree = 0;
return nFree;
+