📄 yaffs_guts.c
字号:
if(yaffs_CheckChunkBit(dev,theChunk / dev->nChunksPerBlock,theChunk % dev->nChunksPerBlock))
{
yaffs_ReadChunkWithTagsFromNAND(dev,theChunk,NULL,tags);
if(yaffs_TagsMatch(tags,objectId,chunkInInode))
{
// found it;
return theChunk;
}
}
theChunk++;
}
return -1;
}
// DeleteWorker scans backwards through the tnode tree and deletes all the
// chunks and tnodes in the file
// Returns 1 if the tree was deleted. Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset,int *limit)
{
int i;
int chunkInInode;
int theChunk;
yaffs_ExtendedTags tags;
int foundChunk;
yaffs_Device *dev = in->myDev;
int allDone = 1;
if(tn)
{
if(level > 0)
{
for(i = YAFFS_NTNODES_INTERNAL -1; allDone && i >= 0; i--)
{
if(tn->internal[i])
{
if(limit && (*limit) < 0)
{
allDone = 0;
}
else
{
allDone = yaffs_DeleteWorker(in,tn->internal[i],level - 1,
(chunkOffset << YAFFS_TNODES_INTERNAL_BITS ) + i ,limit);
}
if(allDone)
{
yaffs_FreeTnode(dev,tn->internal[i]);
tn->internal[i] = NULL;
}
}
}
return (allDone) ? 1 : 0;
}
else if(level == 0)
{
int hitLimit = 0;
for(i = YAFFS_NTNODES_LEVEL0 -1; i >= 0 && !hitLimit; i--)
{
if(tn->level0[i])
{
chunkInInode = (chunkOffset << YAFFS_TNODES_LEVEL0_BITS ) + i;
theChunk = tn->level0[i] << dev->chunkGroupBits;
foundChunk = yaffs_FindChunkInGroup(dev,theChunk,&tags,in->objectId,chunkInInode);
if(foundChunk > 0)
{
yaffs_DeleteChunk(dev,foundChunk,1,__LINE__);
in->nDataChunks--;
if(limit)
{
*limit = *limit-1;
if(*limit <= 0)
{
hitLimit = 1;
}
}
}
tn->level0[i] = 0;
}
}
return (i < 0) ? 1 : 0;
}
}
return 1;
}
static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk)
{
yaffs_BlockInfo *theBlock;
T(YAFFS_TRACE_DELETE,(TSTR("soft delete chunk %d" TENDSTR),chunk));
theBlock = yaffs_GetBlockInfo(dev, chunk/dev->nChunksPerBlock);
if(theBlock)
{
theBlock->softDeletions++;
}
}
// SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
// All soft deleting does is increment the block's softdelete count and pulls the chunk out
// of the tnode.
// THus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
//
static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset)
{
int i;
int theChunk;
int allDone = 1;
yaffs_Device *dev = in->myDev;
if(tn)
{
if(level > 0)
{
for(i = YAFFS_NTNODES_INTERNAL -1; allDone && i >= 0; i--)
{
if(tn->internal[i])
{
allDone = yaffs_SoftDeleteWorker(in,tn->internal[i],level - 1,
(chunkOffset << YAFFS_TNODES_INTERNAL_BITS ) + i);
if(allDone)
{
yaffs_FreeTnode(dev,tn->internal[i]);
tn->internal[i] = NULL;
}
else
{
//Hoosterman... how could this happen.
}
}
}
return (allDone) ? 1 : 0;
}
else if(level == 0)
{
for(i = YAFFS_NTNODES_LEVEL0 -1; i >=0; i--)
{
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] << dev->chunkGroupBits);
yaffs_SoftDeleteChunk(dev,theChunk);
tn->level0[i] = 0;
}
}
return 1;
}
}
return 1;
}
static void yaffs_SoftDeleteFile(yaffs_Object *obj)
{
if(obj->deleted &&
obj->variantType == YAFFS_OBJECT_TYPE_FILE &&
!obj->softDeleted)
{
if(obj->nDataChunks <= 0)
{
// Empty file with no duplicate object headers, just delete it immediately
yaffs_FreeTnode(obj->myDev,obj->variant.fileVariant.top);
obj->variant.fileVariant.top = NULL;
T(YAFFS_TRACE_TRACING,(TSTR("yaffs: Deleting empty file %d" TENDSTR),obj->objectId));
yaffs_DoGenericObjectDeletion(obj);
}
else
{
yaffs_SoftDeleteWorker(obj, obj->variant.fileVariant.top, obj->variant.fileVariant.topLevel, 0);
obj->softDeleted = 1;
}
}
}
// Pruning removes any part of the file structure tree that is beyond the
// bounds of the file (ie that does not point to chunks).
//
// A file should only get pruned when its size is reduced.
//
// Before pruning, the chunks must be pulled from the tree and the
// level 0 tnode entries must be zeroed out.
// Could also use this for file deletion, but that's probably better handled
// by a special case.
// yaffs_PruneWorker should only be called by yaffs_PruneFileStructure()
static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn, __u32 level, int del0)
{
int i;
int hasData;
if(tn)
{
hasData = 0;
for(i = 0; i < YAFFS_NTNODES_INTERNAL; i++)
{
if(tn->internal[i] && level > 0)
{
tn->internal[i] = yaffs_PruneWorker(dev,tn->internal[i],level - 1, ( i == 0) ? del0 : 1);
}
if(tn->internal[i])
{
hasData++;
}
}
if(hasData == 0 && del0)
{
// Free and return NULL
yaffs_FreeTnode(dev,tn);
tn = NULL;
}
}
return tn;
}
static int yaffs_PruneFileStructure(yaffs_Device *dev, yaffs_FileStructure *fStruct)
{
int i;
int hasData;
int done = 0;
yaffs_Tnode *tn;
if(fStruct->topLevel > 0)
{
fStruct->top = yaffs_PruneWorker(dev,fStruct->top, fStruct->topLevel,0);
// Now we have a tree with all the non-zero branches NULL but the height
// is the same as it was.
// Let's see if we can trim internal tnodes to shorten the tree.
// We can do this if only the 0th element in the tnode is in use
// (ie all the non-zero are NULL)
while(fStruct->topLevel && !done)
{
tn = fStruct->top;
hasData = 0;
for(i = 1; i <YAFFS_NTNODES_INTERNAL; i++)
{
if(tn->internal[i])
{
hasData++;
}
}
if(!hasData)
{
fStruct->top = tn->internal[0];
fStruct->topLevel--;
yaffs_FreeTnode(dev,tn);
}
else
{
done = 1;
}
}
}
return YAFFS_OK;
}
/////////////////////// End of File Structure functions. /////////////////
// yaffs_CreateFreeObjects creates a bunch more objects and
// adds them to the object free list.
static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
{
int i;
yaffs_Object *newObjects;
yaffs_ObjectList *list;
if(nObjects < 1) return YAFFS_OK;
// make these things
newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
if (!newObjects)
{
T(YAFFS_TRACE_ALLOCATE,(TSTR("yaffs: Could not allocate more objects" TENDSTR)));
return YAFFS_FAIL;
}
// Hook them into the free list
for(i = 0; i < nObjects - 1; i++)
{
newObjects[i].siblings.next = (struct list_head *)(&newObjects[i+1]);
}
newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects;
dev->freeObjects = newObjects;
dev->nFreeObjects+= nObjects;
dev->nObjectsCreated+= nObjects;
// Now add this bunch of Objects to a list for freeing up.
list = YMALLOC(sizeof(yaffs_ObjectList));
if(!list)
{
T(YAFFS_TRACE_ALLOCATE,(TSTR("Could not add objects to management list" TENDSTR)));
}
else
{
list->objects = newObjects;
list->next = dev->allocatedObjectList;
dev->allocatedObjectList = list;
}
return YAFFS_OK;
}
// AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out
static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev)
{
yaffs_Object *tn = NULL;
// If there are none left make more
if(!dev->freeObjects)
{
yaffs_CreateFreeObjects(dev,YAFFS_ALLOCATION_NOBJECTS);
}
if(dev->freeObjects)
{
tn = dev->freeObjects;
dev->freeObjects = (yaffs_Object *)(dev->freeObjects->siblings.next);
dev->nFreeObjects--;
// Now sweeten it up...
memset(tn,0,sizeof(yaffs_Object));
tn->myDev = dev;
tn->chunkId = -1;
tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
INIT_LIST_HEAD(&(tn->hardLinks));
INIT_LIST_HEAD(&(tn->hashLink));
INIT_LIST_HEAD(&tn->siblings);
// Add it to the lost and found directory.
// NB Can't put root or lostNFound in lostNFound so
// check if lostNFound exists first
if(dev->lostNFoundDir)
{
yaffs_AddObjectToDirectory(dev->lostNFoundDir,tn);
}
}
return tn;
}
static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev,int number,__u32 mode)
{
yaffs_Object *obj = yaffs_CreateNewObject(dev,number,YAFFS_OBJECT_TYPE_DIRECTORY);
if(obj)
{
obj->fake = 1; // it is fake so it has no NAND presence...
obj->renameAllowed= 0; // ... and we're not allowed to rename it...
obj->unlinkAllowed= 0; // ... or unlink it
obj->deleted = 0;
obj->unlinked = 0;
obj->st_mode = mode;
obj->myDev = dev;
obj->chunkId = 0; // Not a valid chunk.
}
return obj;
}
static void yaffs_UnhashObject(yaffs_Object *tn)
{
int bucket;
yaffs_Device *dev = tn->myDev;
// If it is still linked into the bucket list, free from the list
if(!list_empty(&tn->hashLink))
{
list_del_init(&tn->hashLink);
bucket = yaffs_HashFunction(tn->objectId);
dev->objectBucket[bucket].count--;
}
}
// FreeObject frees up a Object and puts it back on the free list
static void yaffs_FreeObject(yaffs_Object *tn)
{
yaffs_Device *dev = tn->myDev;
yaffs_UnhashObject(tn);
// Link into the free list.
tn->siblings.next = (struct list_head *)(dev->freeObjects);
dev->freeObjects = tn;
dev->nFreeObjects++;
}
static void yaffs_DeinitialiseObjects(yaffs_Device *dev)
{
// Free the list of allocated Objects
yaffs_ObjectList *tmp;
while( dev->allocatedObjectList)
{
tmp = dev->allocatedObjectList->next;
YFREE(dev->allocatedObjectList->objects);
YFREE(dev->allocatedObjectList);
dev->allocatedObjectList = tmp;
}
dev->freeObjects = NULL;
dev->nFreeObjects = 0;
}
static void yaffs_InitialiseObjects(yaffs_Device *dev)
{
int i;
dev->allocatedObjectList = NULL;
dev->freeObjects = NULL;
dev->nFreeObjects = 0;
for(i = 0; i < YAFFS_NOBJECT_BUCKETS; i++)
{
INIT_LIST_HEAD(&dev->objectBucket[i].list);
dev->objectBucket[i].count = 0;
}
}
int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
{
static int x = 0;
int i;
int l = 999;
int lowest = 999999;
// First let's see if we can find one that's empty.
for(i = 0; i < 10 && lowest > 0; i++)
{
x++;
x %= YAFFS_NOBJECT_BUCKETS;
if(dev->objectBucket[x].count < lowest)
{
lowest = dev->objectBucket[x].count;
l = x;
}
}
// If we didn't find an empty list, then try
// looking a bit further for a short one
for(i = 0; i < 10 && lowest > 3; i++)
{
x++;
x %= YAFFS_NOBJECT_BUCKETS;
if(dev->objectBucket[x].count < lowest)
{
lowest = dev->objectBucket[x].count;
l = x;
}
}
return l;
}
static int yaffs_CreateNewObjectNumber(yaffs_Device *dev)
{
int bucket = yaffs_FindNiceObjectBucket(dev);
// Now find an object value that has not already been taken
// by scanning the list.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -