📄 yaffs_guts.c
字号:
if(number < 0)
{
number = yaffs_CreateNewObjectNumber(dev);
}
theObject = yaffs_AllocateEmptyObject(dev);
if(theObject)
{
theObject->fake = 0;
theObject->renameAllowed = 1;
theObject->unlinkAllowed = 1;
theObject->objectId = number;
yaffs_HashObject(theObject);
theObject->variantType = type;
#ifdef CONFIG_YAFFS_WINCE
yfsd_WinFileTimeNow(theObject->win_atime);
theObject->win_ctime[0] = theObject->win_mtime[0] = theObject->win_atime[0];
theObject->win_ctime[1] = theObject->win_mtime[1] = theObject->win_atime[1];
#else
theObject->yst_atime = theObject->yst_mtime = theObject->yst_ctime = Y_CURRENT_TIME;
#endif
switch(type)
{
case YAFFS_OBJECT_TYPE_FILE:
theObject->variant.fileVariant.fileSize = 0;
theObject->variant.fileVariant.scannedFileSize = 0;
theObject->variant.fileVariant.topLevel = 0;
theObject->variant.fileVariant.top = yaffs_GetTnode(dev);
break;
case YAFFS_OBJECT_TYPE_DIRECTORY:
INIT_LIST_HEAD(&theObject->variant.directoryVariant.children);
break;
case YAFFS_OBJECT_TYPE_SYMLINK:
// No action required
break;
case YAFFS_OBJECT_TYPE_HARDLINK:
// No action required
break;
case YAFFS_OBJECT_TYPE_SPECIAL:
// No action required
break;
case YAFFS_OBJECT_TYPE_UNKNOWN:
// todo this should not happen
break;
}
}
return theObject;
}
yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, int number,yaffs_ObjectType type)
{
yaffs_Object *theObject = NULL;
if(number > 0)
{
theObject = yaffs_FindObjectByNumber(dev,number);
}
if(!theObject)
{
theObject = yaffs_CreateNewObject(dev,number,type);
}
return theObject;
}
char *yaffs_CloneString(const char *str)
{
char *newStr = NULL;
if(str && *str)
{
newStr = YMALLOC(strlen(str) + 1);
strcpy(newStr,str);
}
return newStr;
}
//
// Mknod (create) a new object.
// 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,
yaffs_Object *parent,
const char *name,
__u32 mode,
__u32 uid,
__u32 gid,
yaffs_Object *equivalentObject,
const char *aliasString,
__u32 rdev)
{
yaffs_Object *in;
yaffs_Device *dev = parent->myDev;
// Check if the entry exists. If it does then fail the call since we don't want a dup.
if(yaffs_FindObjectByName(parent,name))
{
return NULL;
}
in = yaffs_CreateNewObject(dev,-1,type);
if(in)
{
in->chunkId = -1;
in->valid = 1;
in->variantType = type;
in->yst_mode = mode;
#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[1];
#else
in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;
in->yst_rdev = rdev;
in->yst_uid = uid;
in->yst_gid = gid;
#endif
in->nDataChunks = 0;
yaffs_SetObjectName(in,name);
in->dirty = 1;
yaffs_AddObjectToDirectory(parent,in);
in->myDev = parent->myDev;
switch(type)
{
case YAFFS_OBJECT_TYPE_SYMLINK:
in->variant.symLinkVariant.alias = yaffs_CloneString(aliasString);
break;
case YAFFS_OBJECT_TYPE_HARDLINK:
in->variant.hardLinkVariant.equivalentObject = equivalentObject;
in->variant.hardLinkVariant.equivalentObjectId = equivalentObject->objectId;
list_add(&in->hardLinks,&equivalentObject->hardLinks);
break;
case YAFFS_OBJECT_TYPE_FILE: // do nothing
case YAFFS_OBJECT_TYPE_DIRECTORY: // do nothing
case YAFFS_OBJECT_TYPE_SPECIAL: // do nothing
case YAFFS_OBJECT_TYPE_UNKNOWN:
break;
}
if(/*yaffs_GetNumberOfFreeChunks(dev) <= 0 || */
yaffs_UpdateObjectHeader(in,name,0) < 0)
{
// Could not create the object header, fail the creation
yaffs_AbortHalfCreatedObject(in);
in = NULL;
}
}
return in;
}
yaffs_Object *yaffs_MknodFile(yaffs_Object *parent,const char *name, __u32 mode, __u32 uid, __u32 gid)
{
return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE,parent,name,mode,uid,gid,NULL,NULL,0);
}
yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent,const char *name, __u32 mode, __u32 uid, __u32 gid)
{
return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY,parent,name,mode,uid,gid,NULL,NULL,0);
}
yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent,const char *name, __u32 mode, __u32 uid, __u32 gid, __u32 rdev)
{
return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL,parent,name,mode,uid,gid,NULL,NULL,rdev);
}
yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent,const char *name, __u32 mode, __u32 uid, __u32 gid,const char *alias)
{
return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK,parent,name,mode,uid,gid,NULL,alias,0);
}
// NB yaffs_Link returns the object id of the equivalent object.
yaffs_Object *yaffs_Link(yaffs_Object *parent, const char *name, yaffs_Object *equivalentObject)
{
// Get the real object in case we were fed a hard link as an equivalent object
equivalentObject = yaffs_GetEquivalentObject(equivalentObject);
if(yaffs_MknodObject(YAFFS_OBJECT_TYPE_HARDLINK,parent,name,0,0,0,equivalentObject,NULL,0))
{
return equivalentObject;
}
else
{
return NULL;
}
}
static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const char *newName,int force)
{
int unlinkOp;
if(newDir == NULL)
{
newDir = obj->parent; // use the old directory
}
unlinkOp = (newDir == obj->myDev->unlinkedDir && obj->variantType == YAFFS_OBJECT_TYPE_FILE);
// 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||
force ||
!yaffs_FindObjectByName(newDir,newName)) &&
newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
{
yaffs_SetObjectName(obj,newName);
obj->dirty = 1;
yaffs_AddObjectToDirectory(newDir,obj);
if(unlinkOp) obj->unlinked = 1;
if(yaffs_UpdateObjectHeader(obj,newName,0) >= 0)
{
return YAFFS_OK;
}
}
return YAFFS_FAIL;
}
int yaffs_RenameObject(yaffs_Object *oldDir, const char *oldName, yaffs_Object *newDir, const char *newName)
{
yaffs_Object *obj;
int force = 0;
#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
if(oldDir == newDir && _stricmp(oldName,newName) == 0)
{
force = 1;
}
#endif
obj = yaffs_FindObjectByName(oldDir,oldName);
if(obj && obj->renameAllowed)
{
return yaffs_ChangeObjectName(obj,newDir,newName,force);
}
return YAFFS_FAIL;
}
#if 0
//defined but not used
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++)
{
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;
}
#endif
#if 0
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);
for(j = 0; j < 10; j++)
{
//T(("%d\n",j));
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);
}
}
#endif
/////////////////////////// Block Management and Page Allocation ///////////////////
static int yaffs_InitialiseBlocks(yaffs_Device *dev,int nBlocks)
{
dev->allocationBlock = -1; // force it to get a new one
//Todo we're assuming the malloc will pass.
dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo));
// Set up dynamic blockinfo stuff.
dev->chunkBitmapStride = (dev->nChunksPerBlock+7)/8;
dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks);
if(dev->blockInfo && dev->chunkBits)
{
memset(dev->blockInfo,0,nBlocks * sizeof(yaffs_BlockInfo));
memset(dev->chunkBits,0,dev->chunkBitmapStride * nBlocks);
return YAFFS_OK;
}
return YAFFS_FAIL;
}
static void yaffs_DeinitialiseBlocks(yaffs_Device *dev)
{
YFREE(dev->blockInfo);
dev->blockInfo = NULL;
YFREE(dev->chunkBits);
dev->chunkBits = NULL;
}
// FindDiretiestBlock is used to select the dirtiest block (or close enough)
// for garbage collection.
static int yaffs_FindDirtiestBlock(yaffs_Device *dev,int aggressive)
{
int b = dev->currentDirtyChecker;
int i;
int iterations;
int dirtiest = -1;
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->internalEndBlock - dev->internalStartBlock + 1;
}
else
{
iterations = dev->internalEndBlock - dev->internalStartBlock + 1;
iterations = iterations / 16;
if(iterations > 200)
{
iterations = 200;
}
}
for(i = 0; i <= iterations && pagesInUse > 0 ; i++)
{
b++;
if ( b < dev->internalStartBlock || b > dev->internalEndBlock)
{
b = dev->internalStartBlock;
}
if(b < dev->internalStartBlock || b > dev->internalEndBlock)
{
T(YAFFS_TRACE_ERROR,(TSTR("**>> Block %d is not valid" TENDSTR),b));
YBUG();
}
bi = yaffs_GetBlockInfo(dev,b);
if(bi->blockState == YAFFS_BLOCK_STATE_FULL &&
(bi->pagesInUse - bi->softDeletions )< pagesInUse)
{
dirtiest = b;
pagesInUse = (bi->pagesInUse - bi->softDeletions);
}
}
dev->currentDirtyChecker = b;
return dirtiest;
}
static void yaffs_BlockBecameDirty(yaffs_Device *dev,int blockNo)
{
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,blockNo);
int erasedOk = 0;
// If the block is still healthy erase it and mark as clean.
// If the block has had a data failure, then retire it.
bi->blockState = YAFFS_BLOCK_STATE_DIRTY;
if(!bi->needsRetiring)
{
erasedOk = yaffs_EraseBlockInNAND(dev,blockNo);
if(!erasedOk)
{
T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>> Erasure failed %d" TENDSTR),blockNo));
}
}
if( erasedOk )
{
// Clean it up...
bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
dev->nErasedBlocks++;
bi->pagesInUse = 0;
bi->softDeletions = 0;
yaffs_ClearChunkBits(dev,blockNo);
T(YAFFS_TRACE_ERASE,(TSTR("Erased block %d" TENDSTR),blockNo));
}
else
{
yaffs_RetireBlock(dev,blockNo);
T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>> Block %d retired" TENDSTR),blockNo));
}
}
static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
{
int i;
yaffs_BlockInfo *bi;
if(dev->nErasedBlocks < 1)
{
// Hoosterman we've got a problem.
// Can't get space to gc
T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: no space during gc" TENDSTR)));
return -1;
}
// Find an empty block.
for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++)
{
dev->allocationBlockFinder++;
if(dev->allocationBlockFinder <dev->internalStartBlock || dev->allocationBlockFinder> dev->internalEndBlock)
{
dev->allocationBlockFinder = dev->internalStartBlock;
}
bi = yaffs_GetBlockInfo(dev,dev->allocationBlockFinder);
if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
{
bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING;
dev->nErasedBlocks--;
return dev->allocationBlockFinder;
}
}
return -1;
}
static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve)
{
int retVal;
yaffs_BlockInfo *bi;
if(dev->allocationBlock < 0)
{
// Get next block to allocate off
dev->allocationBlock = yaffs_FindBlockForAllocation(dev);
dev->allocationPage = 0;
}
if(!useReserve && dev->nErasedBlocks <= dev->nReservedBlocks)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -