📄 yaffs_guts.c
字号:
} return NULL;}yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type){ yaffs_Object *theObject; 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->st_atime = theObject->st_mtime = theObject->st_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;}YCHAR *yaffs_CloneString(const YCHAR *str){ YCHAR *newStr = NULL; if(str && *str) { newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR)); yaffs_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 YCHAR *name, __u32 mode, __u32 uid, __u32 gid, yaffs_Object *equivalentObject, const YCHAR *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) < 0) { // Could not create the object header, fail the creation yaffs_DestroyObject(in); in = NULL; } } return in;}yaffs_Object *yaffs_MknodFile(yaffs_Object *parent,const YCHAR *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 YCHAR *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 YCHAR *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 YCHAR *name, __u32 mode, __u32 uid, __u32 gid,const YCHAR *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 YCHAR *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 YCHAR *newName,int force){ int unlinkOp; int deleteOp; if(newDir == NULL) { newDir = obj->parent; // use the old directory } // TODO: Do we need this different handling for YAFFS2 and YAFFS1?? if(obj->myDev->isYaffs2) { unlinkOp = (newDir == obj->myDev->unlinkedDir); } else { unlinkOp = (newDir == obj->myDev->unlinkedDir && obj->variantType == YAFFS_OBJECT_TYPE_FILE); } deleteOp = (newDir == obj->myDev->deletedDir); // 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|| deleteOp || 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 it is a dletion then we mark it as a shrink for gc purposes. if(yaffs_UpdateObjectHeader(obj,newName,0,deleteOp) >= 0) { return YAFFS_OK; } } return YAFFS_FAIL;}int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName, yaffs_Object *newDir, const YCHAR *newName){ yaffs_Object *obj; int force = 0; #ifdef CONFIG_YAFFS_CASE_INSENSITIVE // Special case for case insemsitive systems (eg. 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 && yaffs_strcmp(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;}static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device *dev, yaffs_BlockInfo *bi){ int i; __u32 seq; yaffs_BlockInfo *b; if(!dev->isYaffs2) return 1; // disqualification only applies to yaffs2. if(!bi->hasShrinkHeader) return 1; // can gc // Find the oldest dirty sequence number if we don't know it and save it // so we don't have to keep recomputing it. if(!dev->oldestDirtySequence) { seq = dev->sequenceNumber; for(i = dev->startBlock; i <= dev->endBlock; i++) { b = yaffs_GetBlockInfo(dev,i); if(b->blockState == YAFFS_BLOCK_STATE_FULL && (b->pagesInUse - b->softDeletions )< dev->nChunksPerBlock && b->sequenceNumber < seq) { seq = b->sequenceNumber; } } dev->oldestDirtySequence = seq; } // Can't do gc of this block if there are any blocks older than this one that have // discarded pages. return (bi->sequenceNumber <= dev->oldestDirtySequence); return 1;}// FindDiretiestBlock is used to select the dirtiest block (or close enough)// for garbage collection.//static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,int aggressive){ int b = dev->currentDirtyChecker; int i; int iterations; int dirtiest = -1; int pagesInUse; yaffs_BlockInfo *bi; static int nonAggressiveSkip = 0; // If we're doing aggressive GC then we are happy to take a less-dirty block, and // search harder. // else (we're doing a leasurely gc), then we only bother to do this if the // block has only a few pages in use. nonAggressiveSkip--; if(!aggressive &&(nonAggressiveSkip > 0)) { return -1; } 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 && yaffs_BlockNotDisqualifiedFromGC(dev,bi)) { dirtiest = b; pagesInUse = (bi->pagesInUse - bi->softDeletions); } } dev->currentDirtyChecker = b; if(dirtiest > 0) { T(YAFFS_TRACE_GC,(TSTR("GC Selected block %d with %d free" TENDSTR),dirtiest,dev->nChunksPerBlock - pagesInUse)); } dev->oldestDirtySequence = 0; // clear this if(dirtiest > 0) { nonAggressiveSkip = 4; } 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) { dev->nErasureFailures++; T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>> Erasure failed %d" TENDSTR),blockNo)); } } if(erasedOk && (yaffs_traceMask & YAFFS_TRACE_ERASE)) { int i; for(i = 0; i < dev->nChunksPerBlock; i++) { if(!yaffs_CheckChunkErased(dev,blockNo * dev->nChunksPerBlock + i)) { T(YAFFS_TRACE_ERROR,(TSTR(">>Block %d erasure supposedly OK, but chunk %d not erased" TENDSTR),blockNo,i));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -