📄 yaffs_guts.c
字号:
{ 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_SPECIAL, 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);}/* 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 shadows){ int unlinkOp; int deleteOp; yaffs_Object *existingTarget; if (newDir == NULL) { newDir = obj->parent; /* use the old directory */ } if (newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { T(YAFFS_TRACE_ALWAYS, (TSTR ("tragendy: yaffs_ChangeObjectName: newDir is not a directory" TENDSTR))); YBUG(); } /* 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); existingTarget = yaffs_FindObjectByName(newDir, newName); /* 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. * else only proceed if the new name does not exist and if we're putting * it into a directory. */ if ((unlinkOp || deleteOp || force || (shadows > 0) || !existingTarget) && 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 deletion then we mark it as a shrink for gc purposes. */ if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows)>= 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; yaffs_Object *existingTarget; 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); /* Check new name to long. */ if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK && yaffs_strlen(newName) > YAFFS_MAX_ALIAS_LENGTH) /* ENAMETOOLONG */ return YAFFS_FAIL; else if (obj->variantType != YAFFS_OBJECT_TYPE_SYMLINK && yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH) /* ENAMETOOLONG */ return YAFFS_FAIL; if (obj && obj->renameAllowed) { /* Now do the handling for an existing target, if there is one */ existingTarget = yaffs_FindObjectByName(newDir, newName); if (existingTarget && existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY && !list_empty(&existingTarget->variant.directoryVariant.children)) { /* There is a target that is a non-empty directory, so we fail */ return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */ } else if (existingTarget && existingTarget != obj) { /* Nuke the target first, using shadowing, * but only if it isn't the same object */ yaffs_ChangeObjectName(obj, newDir, newName, force, existingTarget->objectId); yaffs_UnlinkObject(existingTarget); } return yaffs_ChangeObjectName(obj, newDir, newName, 1, 0); } return YAFFS_FAIL;}/*------------------------- Block Management and Page Allocation ----------------*/static int yaffs_InitialiseBlocks(yaffs_Device * dev){ int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1; 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)); if(!dev->blockInfo){ dev->blockInfo = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockInfo)); dev->blockInfoAlt = 1; } else dev->blockInfoAlt = 0; /* Set up dynamic blockinfo stuff. */ dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; // round up bytes dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks); if(!dev->chunkBits){ dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks); dev->chunkBitsAlt = 1; } else dev->chunkBitsAlt = 0; 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){ if(dev->blockInfoAlt) YFREE_ALT(dev->blockInfo); else YFREE(dev->blockInfo); dev->blockInfoAlt = 0; dev->blockInfo = NULL; if(dev->chunkBitsAlt) YFREE_ALT(dev->chunkBits); else YFREE(dev->chunkBits); dev->chunkBitsAlt = 0; 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->internalStartBlock; i <= dev->internalEndBlock; 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->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 0 if (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT) { dirtiest = b; pagesInUse = 0; } else #endif 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; 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) { yaffs_InvalidateCheckpoint(dev); 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)); } } } if (erasedOk) { /* Clean it up... */ bi->blockState = YAFFS_BLOCK_STATE_EMPTY; dev->nErasedBlocks++; bi->pagesInUse = 0; bi->softDeletions = 0; bi->hasShrinkHeader = 0; yaffs_ClearChunkBits(dev, blockNo); T(YAFFS_TRACE_ERASE, (TSTR("Erased block %d" TENDSTR), blockNo)); } else { dev->nFreeChunks -= dev->nChunksPerBlock; /* We lost a block of free space */ 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 more eraased blocks" 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->sequenceNumber++; bi->sequenceNumber = dev->sequenceNumber; dev->nErasedBlocks--; T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocated block %d, seq %d, %d left" TENDSTR), dev->allocationBlockFinder, dev->sequenceNumber, dev->nErasedBlocks)); return dev->allocationBlockFinder; } } T(YAFFS_TRACE_ALWAYS, (TSTR ("yaffs tragedy: no more eraased blocks, but there should have been %d" TENDSTR), dev->nErasedBlocks)); return -1;}// Check if there's space to allocate...// Thinks.... do we need top make this ths same as yaffs_GetFreeChunks()?static int yaffs_CheckSpaceForAllocation(yaffs_Device * dev){ int reservedChunks; int reservedBlocks = dev->nReservedBlocks; int checkpointBlocks; checkpointBlocks = dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint; if(checkpointBlocks < 0) checkpointBlocks = 0; reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->nChunksPerBlock); return (dev->nFreeChunks > reservedChunks);}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 && !yaffs_CheckSpaceForAllocation(dev)) { /* Not enough space to allocate unless we're allowed to use the reserve. */ return -1; } if (dev->nErasedBlocks < dev->nReservedBlocks && dev->allocationPage == 0) { T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR))); } /* 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;}static int yaffs_GetErasedChunks(yaffs_Device * dev){ int n; n = dev->nErasedBlocks * dev->nChunksPerBlock; if (dev->allocationBlock > 0) { n += (dev->nChunksPerBlock - dev->allocationPage); } return n;}static int yaffs_GarbageCollectBlock(yaffs_Device * dev, int block){ int oldChunk; int newChunk; int chunkInBlock; int markNAND; int retVal = YAFFS_OK; int cleanups = 0; int i; int isCheckpointBlock; int chunksBefore = yaffs_GetErasedChunks(dev); int chunksAfter; yaffs_ExtendedTags tags; yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, block); yaffs_Object *object;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -