📄 yaffs_guts.c
字号:
tn->level0[i] = 0;
}
}
return (i < 0) ? 1 : 0;
}
}
return 1;
}
// 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 chunkInInode; // unused
int theChunk;
yaffs_BlockInfo *theBlock;
// yaffs_Tags tags; // unused
// int found;
// int chunkDeleted;
int allDone = 1;
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(in->myDev,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] << in->myDev->chunkGroupBits);
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++;
}
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, 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->yst_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;
#ifdef __KERNEL__
if(tn->myInode)
{
// We're still hooked up to a cached inode.
// Don't delete now, but mark for later deletion
tn->deferedFree = 1;
return;
}
#endif
yaffs_UnhashObject(tn);
// Link into the free list.
tn->siblings.next = (struct list_head *)(dev->freeObjects);
dev->freeObjects = tn;
dev->nFreeObjects++;
}
#ifdef __KERNEL__
void yaffs_HandleDeferedFree(yaffs_Object *obj)
{
if(obj->deferedFree)
{
yaffs_FreeObject(obj);
}
}
#endif
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.
int found = 0;
struct list_head *i;
__u32 n = (__u32)bucket;
//yaffs_CheckObjectHashSanity();
while(!found)
{
found = 1;
n += YAFFS_NOBJECT_BUCKETS;
if(1 ||dev->objectBucket[bucket].count > 0)
{
list_for_each(i,&dev->objectBucket[bucket].list)
{
// If there is already one in the list
if(i && list_entry(i, yaffs_Object,hashLink)->objectId == n)
{
found = 0;
}
}
}
}
//T(("bucket %d count %d inode %d\n",bucket,yaffs_objectBucket[bucket].count,n);
return n;
}
void yaffs_HashObject(yaffs_Object *in)
{
int bucket = yaffs_HashFunction(in->objectId);
yaffs_Device *dev = in->myDev;
if(!list_empty(&in->hashLink))
{
//YINFO("!!!");
}
list_add(&in->hashLink,&dev->objectBucket[bucket].list);
dev->objectBucket[bucket].count++;
}
yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev,__u32 number)
{
int bucket = yaffs_HashFunction(number);
struct list_head *i;
yaffs_Object *in;
list_for_each(i,&dev->objectBucket[bucket].list)
{
// Look if it is in the list
if(i)
{
in = list_entry(i, yaffs_Object,hashLink);
if(in->objectId == number)
{
#ifdef __KERNEL__
// Don't tell the VFS about this if it has been marked for freeing
if(in->deferedFree)
return NULL;
#endif
return in;
}
}
}
return NULL;
}
yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type)
{
yaffs_Object *theObject;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -