⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 yaffs_guts.c

📁 YAFFS的升级版本YAFFS2
💻 C
📖 第 1 页 / 共 5 页
字号:
	// 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));
					}
			}
	}
	
	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
	{
		yaffs_RetireBlock(dev,blockNo);
		T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>> Block %d retired" TENDSTR),blockNo));
	}
}

static void yaffs_DumpBlockStats(yaffs_Device *dev)
{
	int i,j;
	yaffs_BlockInfo *bi;
	
	for(i= dev->startBlock; i <=dev->endBlock; i++)
	{
		bi = yaffs_GetBlockInfo(dev,i);
		T(YAFFS_TRACE_ALLOCATE,(TSTR("%3d state %d shrink %d inuse %d/%d seq %d pages"),i,
		bi->blockState,bi->hasShrinkHeader,bi->pagesInUse,bi->softDeletions,bi->sequenceNumber));	
		
		for(j = 0; j < dev->nChunksPerBlock; j++)
		{
			if(yaffs_CheckChunkBit(dev,i,j))
			{
				T(YAFFS_TRACE_ALLOCATE,(TSTR(" %d"),j));

			}
		}
		T(YAFFS_TRACE_ALLOCATE,(TSTR(" " TENDSTR)));

	}
}


static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
{
	int i;
	
	yaffs_BlockInfo *bi;
	
#if 0
	static int j = 0;
	j++;
	if(j < 0 || j > 100)
	{
		j = 0;
		yaffs_DumpBlockStats(dev);
	}
	
#endif
	
	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->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->sequenceNumber++;
			bi->sequenceNumber = dev->sequenceNumber;
			dev->nErasedBlocks--;		
			T(YAFFS_TRACE_ALLOCATE,(TSTR("Allocated block %d, seq  %d" TENDSTR),dev->allocationBlockFinder,dev->sequenceNumber));	
			return dev->allocationBlockFinder;
		}
	}
		T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: no more eraased blocks, but there should have been one" TENDSTR)));

	
	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;
	}

	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;	
}


// 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_GetErasedChunks(yaffs_Device *dev)
{
		int n;

		n = dev->nErasedBlocks * dev->nChunksPerBlock;

		if(dev->allocationBlock> 0)
		{
			n += (dev->nChunksPerBlock - dev->allocationPage);
		}

		return n;

}

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 chunksBefore = yaffs_GetErasedChunks(dev);
	int chunksAfter;

	yaffs_ExtendedTags  tags;
	
	yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,block);
	
	yaffs_Object *object;
	
	bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;

	T(YAFFS_TRACE_TRACING,(TSTR("Collecting block %d, in use %d, shrink %d, " TENDSTR),block,bi->pagesInUse,bi->hasShrinkHeader));
	//T(("Collecting block %d n %d bits %x\n",block, bi->pagesInUse, bi->pageBits));	

	bi->hasShrinkHeader = 0; // clear the flag so that the block can erase


	if(!yaffs_StillSomeChunkBits(dev,block))
	{
		T(YAFFS_TRACE_TRACING,(TSTR("Collecting block %d that has no chunks in use" TENDSTR),block));
		yaffs_BlockBecameDirty(dev,block);
	}
	else
	{

			__u8  *buffer = yaffs_GetTempBuffer(dev,__LINE__);

	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_InitialiseTags(&tags);
			
			yaffs_ReadChunkWithTagsFromNAND(dev,oldChunk,buffer, &tags);

			object = yaffs_FindObjectByNumber(dev,tags.objectId);
			
			T(YAFFS_TRACE_GC_DETAIL,(TSTR("Collecting page %d, %d %d %d " TENDSTR),chunkInBlock,tags.objectId,tags.chunkId,tags.byteCount));
			
			if(!object)
			{
				T(YAFFS_TRACE_ERROR,(TSTR("page %d in gc has no object " TENDSTR),oldChunk));
			}
			
			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)
				{
					// remeber to clean up the object
					dev->gcCleanupList[cleanups] = tags.objectId;
					cleanups++;
 				}
				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
				tags.serialNumber++;

				dev->nGCCopies++;

				newChunk = yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags,1);
			
				if(newChunk < 0)
				{
					retVal =  YAFFS_FAIL;
				}
				else
				{
			
					// Ok, now fix up the Tnodes etc.
			
					if(tags.chunkId == 0)
					{
						// It's a header
						object->chunkId = newChunk;
						object->serial = tags.serialNumber;
					}
					else
					{
						// It's a data chunk
						yaffs_PutChunkIntoFile(object, tags.chunkId, newChunk,0);
					}
				}
			}
			
			yaffs_DeleteChunk(dev,oldChunk,markNAND,__LINE__);			
			
		}
	}

	yaffs_ReleaseTempBuffer(dev,buffer,__LINE__);


	// Do any required cleanups
	for(i = 0; i < cleanups; i++)
	{						
		// Time to delete the file too
		object =  yaffs_FindObjectByNumber(dev,dev->gcCleanupList[i]);
		if(object)
		{
			yaffs_FreeTnode(dev,object->variant.fileVariant.top);
			object->variant.fileVariant.top = NULL;
			T(YAFFS_TRACE_GC,(TSTR("yaffs: About to finally delete object %d" TENDSTR),object->objectId));
			yaffs_DoGenericObjectDeletion(object);
		}

	}

	}

	if(chunksBefore >= (chunksAfter = yaffs_GetErasedChunks(dev)))
	{
			T(YAFFS_TRACE_GC,(TSTR("gc did not increase free chunks before %d after %d" TENDSTR),chunksBefore,chunksAfter));
	}
			
	return YAFFS_OK;
}

#if 0
static yaffs_Object *yaffs_FindDeletedUnlinkedFile(yaffs_Device *dev)
{
	// find a file to delete
	struct list_head *i;	
	yaffs_Object *l;


	//Scan the unlinked files looking for one to delete
	list_for_each(i,&dev->unlinkedDir->variant.directoryVariant.children)
	{
		if(i)
		{
			l = list_entry(i, yaffs_Object,siblings);
			if(l->deleted)
			{
				return l;			
			}
		}
	}	
	return NULL;
}


static void yaffs_DoUnlinkedFileDeletion(yaffs_Device *dev)
{
	// This does background deletion on unlinked files.. only deleted ones.
	// If we don't have a file we're working on then find one
	if(!dev->unlinkedDeletion && dev->nDeletedFiles > 0)
	{
		dev->unlinkedDeletion = yaffs_FindDeletedUnlinkedFile(dev);
	}
	
	// OK, we're working on a file...
	if(dev->unlinkedDeletion)
	{
		yaffs_Object *obj = dev->unlinkedDeletion;
		int delresult;
		int limit; // Number of chunks to delete in a file.
				   // NB this can be exceeded, but not by much.
				   
		limit = -1;

		delresult = yaffs_DeleteWorker(obj, obj->variant.fileVariant.top, obj->variant.fileVariant.topLevel, 0,&limit);
		
		if(obj->nDataChunks == 0)
		{
			// Done all the deleting of data chunks.
			// Now dump the header and clean up
			yaffs_FreeTnode(dev,obj->variant.fileVariant.top);
			obj->variant.fileVariant.top = NULL;
			yaffs_DoGenericObjectDeletion(obj);
			dev->nDeletedFiles--;
			dev->nUnlinkedFiles--;
			dev->nBackgroundDeletions++;
			dev->unlinkedDeletion = NULL;	
		}
	}
}

#endif

#if 0
#define YAFFS_GARBAGE_COLLECT_LOW_WATER 2
static int yaffs_CheckGarbageCollection(yaffs_Device *dev)
{
	int block;
	int aggressive=0;
	
	//yaffs_DoUnlinkedFileDeletion(dev);
	
	if(dev->nErasedBlocks <= (dev->nReservedBlocks + YAFFS_GARBAGE_COLLECT_LOW_WATER))
	{
		aggressive = 1;
	}		
	
	if(aggressive)
	{
		block = yaffs_FindBlockForGarbageCollection(dev,aggressive);
		
		if(block >= 0)
		{
			dev->garbageCollections++;
			return yaffs_GarbageCollectBlock(dev,block);
		}	
		else
		{
			return YAFFS_FAIL;
		}
	}

	return YAFFS_OK;
}
#endif

// New garbage collector
// If we're very low on erased blocks then we do aggressive garbage collection
// otherwise we do "leasurely" garbage collection.
// Aggressive gc looks further (whole array) and will accept dirtier blocks.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -