📄 yaffs_guts.c
字号:
//// 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->st_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->st_atime = in->st_mtime = in->st_ctime = Y_CURRENT_TIME; in->st_rdev = rdev; in->st_uid = uid; in->st_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_DIRECTORY,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;}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;}#if 0void 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->endBlock - dev->startBlock + 1; } else { iterations = dev->endBlock - dev->startBlock + 1; iterations = iterations / 16; if(iterations > 200) { iterations = 200; } } for(i = 0; i <= iterations && pagesInUse > 0 ; i++) { b++; if ( b < dev->startBlock || b > dev->endBlock) { b = dev->startBlock; } if(b < dev->startBlock || b > dev->endBlock) { 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->startBlock; i <= dev->endBlock; i++) { dev->allocationBlockFinder++; if(dev->allocationBlockFinder <dev->startBlock || dev->allocationBlockFinder> dev->endBlock) { dev->allocationBlockFinder = dev->startBlock; } 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) { // 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -