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

📄 yaffs_guts.c

📁 YAFFS
💻 C
📖 第 1 页 / 共 5 页
字号:
	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));	/*yaffs_VerifyFreeChunks(dev); */	bi->hasShrinkHeader = 0;	/* clear the flag so that the block can erase */	/* Take off the number of soft deleted entries because	 * they're going to get really deleted during GC.	 */	dev->nFreeChunks -= bi->softDeletions;	dev->isDoingGC = 1;	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;				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 soft deleted data chunk,					 * No need to copy this, just forget about it and 					 * fix up the object.					 */					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++;					if (tags.chunkId == 0) {						/* It is an object Id,						 * We need to nuke the shrinkheader flags first						 * We no longer want the shrinkHeader flag since its work is done						 * and if it is left in place it will mess up scanning.						 * Also, clear out any shadowing stuff						 */						yaffs_ObjectHeader *oh;						oh = (yaffs_ObjectHeader *)buffer;						oh->isShrink = 0;						oh->shadowsObject = -1;						tags.extraShadows = 0;						tags.extraIsShrinkHeader = 0;					}					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));	}	dev->isDoingGC = 0;	return YAFFS_OK;}/* 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 less dirty blocks. * Passive gc only inspects smaller areas and will only accept more dirty blocks. * * The idea is to help clear out space in a more spread-out manner. * Dunno if it really does anything useful. */static int yaffs_CheckGarbageCollection(yaffs_Device * dev){	int block;	int aggressive;	int gcOk = YAFFS_OK;	int maxTries = 0;	if (dev->isDoingGC) {		/* Bail out so we don't get recursive gc */		return YAFFS_OK;	}		/* This loop should pass the first time.	 * We'll only see looping here if the erase of the collected block fails.	 */	do {		maxTries++;		if (dev->nErasedBlocks < dev->nReservedBlocks) {			/* We need a block soon...*/			aggressive = 1;		} else {			/* We're in no hurry */			aggressive = 0;		}		block = yaffs_FindBlockForGarbageCollection(dev, aggressive);		if (block > 0) {			dev->garbageCollections++;			if (!aggressive) {				dev->passiveGarbageCollections++;			}			T(YAFFS_TRACE_GC,			  (TSTR			   ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),			   dev->nErasedBlocks, aggressive));			gcOk = yaffs_GarbageCollectBlock(dev, block);		}		if (dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0) {			T(YAFFS_TRACE_GC,			  (TSTR			   ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d"			    TENDSTR), dev->nErasedBlocks, maxTries, block));		}	} while ((dev->nErasedBlocks < dev->nReservedBlocks) && (block > 0)		 && (maxTries < 2));	return aggressive ? gcOk : YAFFS_OK;}/*-------------------------  TAGS --------------------------------*/static int yaffs_TagsMatch(const yaffs_ExtendedTags * tags, int objectId,			   int chunkInObject){	return (tags->chunkId == chunkInObject &&		tags->objectId == objectId && !tags->chunkDeleted) ? 1 : 0;}/*-------------------- Data file manipulation -----------------*/static int yaffs_FindChunkInFile(yaffs_Object * in, int chunkInInode,				 yaffs_ExtendedTags * tags){	/*Get the Tnode, then get the level 0 offset chunk offset */	yaffs_Tnode *tn;	int theChunk = -1;	yaffs_ExtendedTags localTags;	int retVal = -1;	yaffs_Device *dev = in->myDev;	if (!tags) {		/* Passed a NULL, so use our own tags space */		tags = &localTags;	}	tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);	if (tn) {		theChunk = yaffs_GetChunkGroupBase(dev,tn,chunkInInode);		retVal =		    yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,					   chunkInInode);	}	return retVal;}static int yaffs_FindAndDeleteChunkInFile(yaffs_Object * in, int chunkInInode,					  yaffs_ExtendedTags * tags){	/* Get the Tnode, then get the level 0 offset chunk offset */	yaffs_Tnode *tn;	int theChunk = -1;	yaffs_ExtendedTags localTags;	yaffs_Device *dev = in->myDev;	int retVal = -1;	if (!tags) {		/* Passed a NULL, so use our own tags space */		tags = &localTags;	}	tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);	if (tn) {		theChunk = yaffs_GetChunkGroupBase(dev,tn,chunkInInode);		retVal =		    yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,					   chunkInInode);		/* Delete the entry in the filestructure (if found) */		if (retVal != -1) {			yaffs_PutLevel0Tnode(dev,tn,chunkInInode,0);		}	} else {		/*T(("No level 0 found for %d\n", chunkInInode)); */	}	if (retVal == -1) {		/* T(("Could not find %d to delete\n",chunkInInode)); */	}	return retVal;}#ifdef YAFFS_PARANOIDstatic int yaffs_CheckFileSanity(yaffs_Object * in){	int chunk;	int nChunks;	int fSize;	int failed = 0;	int objId;	yaffs_Tnode *tn;	yaffs_Tags localTags;	yaffs_Tags *tags = &localTags;	int theChunk;	int chunkDeleted;	if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {		/* T(("Object not a file\n")); */		return YAFFS_FAIL;	}	objId = in->objectId;	fSize = in->variant.fileVariant.fileSize;	nChunks =	    (fSize + in->myDev->nBytesPerChunk - 1) / in->myDev->nBytesPerChunk;	for (chunk = 1; chunk <= nChunks; chunk++) {		tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant,					   chunk);		if (tn) {			theChunk = yaffs_GetChunkGroupBase(dev,tn,chunk);			if (yaffs_CheckChunkBits			    (dev, theChunk / dev->nChunksPerBlock,			     theChunk % dev->nChunksPerBlock)) {				yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk,							    tags,							    &chunkDeleted);				if (yaffs_TagsMatch				    (tags, in->objectId, chunk, chunkDeleted)) {					/* found it; */				}			} else {				failed = 1;			}		} else {			/* T(("No level 0 found for %d\n", chunk)); */		}	}	return failed ? YAFFS_FAIL : YAFFS_OK;}#endifstatic int yaffs_PutChunkIntoFile(yaffs_Object * in, int chunkInInode,				  int chunkInNAND, int inScan){	/* NB inScan is zero unless scanning. 	 * For forward scanning, inScan is > 0; 	 * for backward scanning inScan is < 0	 */	 	yaffs_Tnode *tn;	yaffs_Device *dev = in->myDev;	int existingChunk;	yaffs_ExtendedTags existingTags;	yaffs_ExtendedTags newTags;	unsigned existingSerial, newSerial;	if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {		/* Just ignore an attempt at putting a chunk into a non-file during scanning		 * If it is not during Scanning then something went wrong!		 */		if (!inScan) {			T(YAFFS_TRACE_ERROR,			  (TSTR			   ("yaffs tragedy:attempt to put data chunk into a non-file"			    TENDSTR)));			YBUG();		}		yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);		return YAFFS_OK;	}	tn = yaffs_AddOrFindLevel0Tnode(dev, &in->variant.fileVariant,					chunkInInode);	if (!tn) {		return YAFFS_FAIL;	}	existingChunk = yaffs_GetChunkGroupBase(dev,tn,chunkInInode);	if (inScan != 0) {		/* If we're scanning then we need to test for duplicates		 * NB This does not need to be efficient since it should only ever 		 * happen when the power fails during a write, then only one		 * chunk should ever be affected.		 *		 * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO		 * Update: For backward scanning we don't need to re-read tags so this is quite cheap.		 */		if (existingChunk != 0) {			/* NB Right now existing chunk will not be real chunkId if the device >= 32MB			 *    thus we have to do a FindChunkInFile to get the real chunk id.			 *			 * We have a duplicate now we need to decide which one to use:			 *			 * Backwards scanning YAFFS2: The old one is what we use, dump the new one.			 * Forward scanning YAFFS2: The new one is what we use, dump the old one.			 * YAFFS1: Get both sets of tags and compare serial numbers.			 */			if (inScan > 0) {				/* Only do this for forward scanning */				yaffs_ReadChunkWithTagsFromNAND(dev,								chunkInNAND,								NULL, &newTags);				/* Do a proper find */				existingChunk =				    yaffs_FindChunkInFile(in, chunkInInode,							  &existingTags);			}			if (existingChunk <= 0) {				/*Hoosterman - how did this happen? */				T(YAFFS_TRACE_ERROR,				  (TSTR				   ("yaffs tragedy: existing chunk < 0 in scan"				    TENDSTR)));			}			/* NB The deleted flags should be false, otherwise the chunks will 			 * not be loaded during a scan			 */			newSerial = newTags.serialNumber;			existingSerial = existingTags.serialNumber;			if ((inScan > 0) &&			    (in->myDev->isYaffs2 ||			     existingChunk <= 0 ||			     ((existingSerial + 1) & 3) == newSerial)) {				/* Forward scanning.                            				 * Use new				 * Delete the old one and drop through to update the tnode				 */				yaffs_DeleteChunk(dev, existingChunk, 1,						  __LINE__);			} else {				/* Backward scanning or we want to use the existing one				 * Use existing.				 * Delete the new one and return early so that the tnode isn't changed				 */				yaffs_DeleteChunk(dev, chunkInNAND, 1,						  __LINE__);				return YAFFS_OK;			}		}	}	if (existingChunk == 0) {		in->nDataChunks++;	}	yaffs_PutLevel0Tnode(dev,tn,chunkInInode,chunkInNAND);	return YAFFS_OK;}static int yaffs_ReadChunkDataFromObject(yaffs_Object * in, int chunkInInode,					 __u8 * buffer){	int chunkInNAND = yaffs_FindChunkInFile(in, chunkInInode, NULL);	if (chunkInNAND >= 0) {		return yaffs_ReadChunkWithTagsFromNAND(in->myDev, chunkInNAND,						       buffer, NULL);	} else {		T(YAFFS_TRACE_NANDACCESS,		  (TSTR("Chunk %d not found zero instead" TENDSTR),		   chunkInNAND));		/* get sane (zero) data if you read a hole */		memset(buffer, 0, in->myDev->nBytesPerChunk);			return 0;	}}void yaffs_DeleteChunk(yaffs_Device * dev, int chunkId, int markNAND, int lyn){	int block;	int page;	yaffs_ExtendedTags tags;	yaffs_BlockInfo *bi;	if

⌨️ 快捷键说明

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