📄 yaffs_guts.c
字号:
// Not enough space to allocate unless we're allowed to use the reserve.
return -1;
}
// Next page please....
if(dev->allocationBlock >= 0)
{
bi = yaffs_GetBlockInfo(dev,dev->allocationBlock);
retVal = (dev->allocationBlock * dev->nChunksPerBlock) +
dev->allocationPage;
bi->pagesInUse++;
yaffs_SetChunkBit(dev,dev->allocationBlock,dev->allocationPage);
dev->allocationPage++;
dev->nFreeChunks--;
// If the block is full set the state to full
if(dev->allocationPage >= dev->nChunksPerBlock)
{
bi->blockState = YAFFS_BLOCK_STATE_FULL;
dev->allocationBlock = -1;
}
return retVal;
}
T(YAFFS_TRACE_ERROR,(TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));
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_GarbageCollectBlock(yaffs_Device *dev,int block)
{
int oldChunk;
int newChunk;
int chunkInBlock;
int markNAND;
yaffs_Spare spare;
yaffs_Tags tags;
__u8 buffer[YAFFS_BYTES_PER_CHUNK];
// yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,block);
yaffs_Object *object;
//T(("Collecting block %d n %d bits %x\n",block, bi->pagesInUse, bi->pageBits));
for(chunkInBlock = 0,oldChunk = block * dev->nChunksPerBlock;
chunkInBlock < dev->nChunksPerBlock && yaffs_StillSomeChunkBits(dev,block);
chunkInBlock++, oldChunk++ )
{
if(yaffs_CheckChunkBit(dev,block,chunkInBlock))
{
// This page is in use and might need to be copied off
markNAND = 1;
//T(("copying page %x from %d to %d\n",mask,oldChunk,newChunk));
yaffs_ReadChunkFromNAND(dev,oldChunk,buffer, &spare,1);
yaffs_GetTagsFromSpare(dev,&spare,&tags);
object = yaffs_FindObjectByNumber(dev,tags.objectId);
if(object && object->deleted && tags.chunkId != 0)
{
// Data chunk in a deleted file, throw it away
// It's a deleted data chunk,
// No need to copy this, just forget about it and fix up the
// object.
//yaffs_PutChunkIntoFile(object, tags.chunkId, 0,0);
object->nDataChunks--;
if(object->nDataChunks <= 0)
{
// Time to delete the file too
yaffs_FreeTnode(object->myDev,object->variant.fileVariant.top);
object->variant.fileVariant.top = NULL;
T(YAFFS_TRACE_TRACING,(TSTR("yaffs: About to finally delete object %d" TENDSTR),object->objectId));
yaffs_DoGenericObjectDeletion(object);
}
markNAND = 0;
}
else if( 0 /* Todo object && object->deleted && object->nDataChunks == 0 */)
{
// Deleted object header with no data chunks.
// Can be discarded and the file deleted.
object->chunkId = 0;
yaffs_FreeTnode(object->myDev,object->variant.fileVariant.top);
object->variant.fileVariant.top = NULL;
yaffs_DoGenericObjectDeletion(object);
}
else if(object)
{
// It's either a data chunk in a live file or
// an ObjectHeader, so we're interested in it.
// NB Need to keep the ObjectHeaders of deleted files
// until the whole file has been deleted off
tags.serialNumber++;
yaffs_LoadTagsIntoSpare(&spare,&tags);
dev->nGCCopies++;
newChunk = yaffs_WriteNewChunkToNAND(dev, buffer, &spare,1);
if(newChunk < 0)
{
return YAFFS_FAIL;
}
// Ok, now fix up the Tnodes etc.
if(tags.chunkId == 0)
{
// It's a header
object->chunkId = newChunk;
object->serial = tags.serialNumber;
}
else
{
// It's a data chunk
yaffs_PutChunkIntoFile(object, tags.chunkId, newChunk,0);
}
}
yaffs_DeleteChunk(dev,oldChunk,markNAND);
}
}
return YAFFS_OK;
}
#if 0
//defined but not used
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;
}
#endif
#if 0
//defined but not used
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
#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 <= (dev->nReservedBlocks + YAFFS_GARBAGE_COLLECT_LOW_WATER))
{
aggressive = 1;
}
if(aggressive)
{
block = yaffs_FindDirtiestBlock(dev,aggressive);
if(block >= 0)
{
dev->garbageCollections++;
return yaffs_GarbageCollectBlock(dev,block);
}
else
{
return YAFFS_FAIL;
}
}
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 ///////////////////////////////////////
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));
}
static int yaffs_ReadChunkTagsFromNAND(yaffs_Device *dev,int chunkInNAND, yaffs_Tags *tags, int *chunkDeleted)
{
if(tags)
{
yaffs_Spare spare;
if(yaffs_ReadChunkFromNAND(dev,chunkInNAND,NULL,&spare,1) == YAFFS_OK)
{
*chunkDeleted = (yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0;
yaffs_GetTagsFromSpare(dev,&spare,tags);
return YAFFS_OK;
}
else
{
return YAFFS_FAIL;
}
}
return YAFFS_OK;
}
#if 0
static int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND, const __u8 *buffer, yaffs_Tags *tags)
{
// 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_WriteChunkToNAND(dev,chunkInNAND,buffer,&spare);
}
#endif
static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, const __u8 *buffer, yaffs_Tags *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);
}
static int yaffs_TagsMatch(const yaffs_Tags *tags, int objectId, int chunkInObject, int chunkDeleted)
{
return ( tags->chunkId == chunkInObject &&
tags->objectId == objectId &&
!chunkDeleted) ? 1 : 0;
}
int yaffs_FindChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_Tags *tags)
{
//Get the Tnode, then get the level 0 offset chunk offset
yaffs_Tnode *tn;
int theChunk = -1;
yaffs_Tags localTags;
int i;
int found = 0;
int chunkDeleted;
yaffs_Device *dev = in->myDev;
if(!tags)
{
// Passed a NULL, so use our own tags space
tags = &localTags;
}
tn = yaffs_FindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
if(tn)
{
theChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits;
// Now we need to do the shifting etc and search for it
for(i = 0,found = 0; theChunk && i < dev->chunkGroupSize && !found; i++)
{
yaffs_ReadChunkTagsFromNAND(dev,theChunk,tags,&chunkDeleted);
if(yaffs_TagsMatch(tags,in->objectId,chunkInInode,chunkDeleted))
{
// found it;
found = 1;
}
else
{
theChunk++;
}
}
}
return found ? theChunk : -1;
}
int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_Tags *tags)
{
//Get the Tnode, then get the level 0 offset chunk offset
yaffs_Tnode *tn;
int theChunk = -1;
yaffs_Tags localTags;
int i;
int found = 0;
yaffs_Device *dev = in->myDev;
int chunkDeleted;
if(!tags)
{
// Passed a NULL, so use our own tags space
tags = &localTags;
}
tn = yaffs_FindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
if(tn)
{
theChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits;
// Now we need to do the shifting etc and search for it
for(i = 0,found = 0; theChunk && i < dev->chunkGroupSize && !found; i++)
{
yaffs_ReadChunkTagsFromNAND(dev,theChunk,tags,&chunkDeleted);
if(yaffs_TagsMatch(tags,in->objectId,chunkInInode,chunkDeleted))
{
// found it;
found = 1;
}
else
{
theChunk++;
}
}
// Delete the entry in the filestructure
if(found)
{
tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] = 0;
}
}
else
{
//T(("No level 0 found for %d\n", chunkInInode));
}
if(!found)
{
//T(("Could not find %d to delete\n",chunkInInode));
}
return found ? theChunk : -1;
}
#ifdef YAFFS_PARANOID
static int yaffs_CheckFileSanity(yaffs_Object *in)
{
int chunk;
int nChunks;
int fSize;
int failed = 0;
int objId;
yaffs_Tnode *tn;
yaffs_Tags localTags;
yaffs_Tags *tags = &localTags;
int theChunk;
int chunkDeleted;
if(in->variantType != YAFFS_OBJECT_TYPE_FILE)
{
//T(("Object not a file\n"));
return YAFFS_FAIL;
}
objId = in->objectId;
fSize = in->variant.fileVariant.fileSize;
nChunks = (fSize + in->myDev->nBytesPerChunk -1)/in->myDev->nBytesPerChunk;
for(chunk
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -