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

📄 yaffs_guts.c

📁 这是ARM yaffs文件系统
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * * Copyright (C) 2002-2007 Aleph One Ltd. *   for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning <charles@aleph1.co.uk> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */const char *yaffs_guts_c_version =    "$Id: yaffs_guts.c,v 1.51 2007/07/23 05:14:08 charles Exp $";#include "yportenv.h"#include "yaffsinterface.h"#include "yaffs_guts.h"#include "yaffs_tagsvalidity.h"#include "yaffs_tagscompat.h"#ifndef  CONFIG_YAFFS_USE_OWN_SORT#include "yaffs_qsort.h"#endif#include "yaffs_nand.h"#include "yaffs_checkptrw.h"#include "yaffs_nand.h"#include "yaffs_packedtags2.h"#ifdef CONFIG_YAFFS_WINCEvoid yfsd_LockYAFFS(BOOL fsLockOnly);void yfsd_UnlockYAFFS(BOOL fsLockOnly);#endif#define YAFFS_PASSIVE_GC_CHUNKS 2#include "yaffs_ecc.h"/* Robustification (if it ever comes about...) */static void yaffs_RetireBlock(yaffs_Device * dev, int blockInNAND);static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND, int erasedOk);static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,				     const __u8 * data,				     const yaffs_ExtendedTags * tags);static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,				    const yaffs_ExtendedTags * tags);/* Other local prototypes */static int yaffs_UnlinkObject( yaffs_Object *obj);static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj);static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList);static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device * dev,					     const __u8 * buffer,					     yaffs_ExtendedTags * tags,					     int useReserve);static int yaffs_PutChunkIntoFile(yaffs_Object * in, int chunkInInode,				  int chunkInNAND, int inScan);static yaffs_Object *yaffs_CreateNewObject(yaffs_Device * dev, int number,					   yaffs_ObjectType type);static void yaffs_AddObjectToDirectory(yaffs_Object * directory,				       yaffs_Object * obj);static int yaffs_UpdateObjectHeader(yaffs_Object * in, const YCHAR * name,				    int force, int isShrink, int shadows);static void yaffs_RemoveObjectFromDirectory(yaffs_Object * obj);static int yaffs_CheckStructures(void);static int yaffs_DeleteWorker(yaffs_Object * in, yaffs_Tnode * tn, __u32 level,			      int chunkOffset, int *limit);static int yaffs_DoGenericObjectDeletion(yaffs_Object * in);static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blockNo);static __u8 *yaffs_GetTempBuffer(yaffs_Device * dev, int lineNo);static void yaffs_ReleaseTempBuffer(yaffs_Device * dev, __u8 * buffer,				    int lineNo);static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,				  int chunkInNAND);static int yaffs_UnlinkWorker(yaffs_Object * obj);static void yaffs_DestroyObject(yaffs_Object * obj);static int yaffs_TagsMatch(const yaffs_ExtendedTags * tags, int objectId,			   int chunkInObject);loff_t yaffs_GetFileSize(yaffs_Object * obj);static int yaffs_AllocateChunk(yaffs_Device * dev, int useReserve, yaffs_BlockInfo **blockUsedPtr);static void yaffs_VerifyFreeChunks(yaffs_Device * dev);static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in);#ifdef YAFFS_PARANOIDstatic int yaffs_CheckFileSanity(yaffs_Object * in);#else#define yaffs_CheckFileSanity(in)#endifstatic void yaffs_InvalidateWholeChunkCache(yaffs_Object * in);static void yaffs_InvalidateChunkCache(yaffs_Object * object, int chunkId);static void yaffs_InvalidateCheckpoint(yaffs_Device *dev);static int yaffs_FindChunkInFile(yaffs_Object * in, int chunkInInode,				 yaffs_ExtendedTags * tags);static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos);static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device * dev,					  yaffs_FileStructure * fStruct,					  __u32 chunkId);/* Function to calculate chunk and offset */static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, __u32 *chunk, __u32 *offset){	if(dev->chunkShift){		/* Easy-peasy power of 2 case */		*chunk  = (__u32)(addr >> dev->chunkShift);		*offset = (__u32)(addr & dev->chunkMask);	}	else if(dev->crumbsPerChunk)	{		/* Case where we're using "crumbs" */		*offset = (__u32)(addr & dev->crumbMask);		addr >>= dev->crumbShift;		*chunk = ((__u32)addr)/dev->crumbsPerChunk;		*offset += ((addr - (*chunk * dev->crumbsPerChunk)) << dev->crumbShift);	}	else		YBUG();}/* Function to return the number of shifts for a power of 2 greater than or equal  * to the given number * Note we don't try to cater for all possible numbers and this does not have to * be hellishly efficient. */ static __u32 ShiftsGE(__u32 x){	int extraBits;	int nShifts;		nShifts = extraBits = 0;		while(x>1){		if(x & 1) extraBits++;		x>>=1;		nShifts++;	}	if(extraBits) 		nShifts++;			return nShifts;}/* Function to return the number of shifts to get a 1 in bit 0 */ static __u32 ShiftDiv(__u32 x){	int nShifts;		nShifts =  0;		if(!x) return 0;		while( !(x&1)){		x>>=1;		nShifts++;	}			return nShifts;}/*  * Temporary buffer manipulations. */static int yaffs_InitialiseTempBuffers(yaffs_Device *dev)	{	int i;	__u8 *buf = (__u8 *)1;			memset(dev->tempBuffer,0,sizeof(dev->tempBuffer));			for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) {		dev->tempBuffer[i].line = 0;	/* not in use */		dev->tempBuffer[i].buffer = buf =		    YMALLOC_DMA(dev->nDataBytesPerChunk);	}			return buf ? YAFFS_OK : YAFFS_FAIL;	}static __u8 *yaffs_GetTempBuffer(yaffs_Device * dev, int lineNo){	int i, j;	for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {		if (dev->tempBuffer[i].line == 0) {			dev->tempBuffer[i].line = lineNo;			if ((i + 1) > dev->maxTemp) {				dev->maxTemp = i + 1;				for (j = 0; j <= i; j++)					dev->tempBuffer[j].maxLine =					    dev->tempBuffer[j].line;			}			return dev->tempBuffer[i].buffer;		}	}	T(YAFFS_TRACE_BUFFERS,	  (TSTR("Out of temp buffers at line %d, other held by lines:"),	   lineNo));	for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {		T(YAFFS_TRACE_BUFFERS, (TSTR(" %d "), dev->tempBuffer[i].line));	}	T(YAFFS_TRACE_BUFFERS, (TSTR(" " TENDSTR)));	/*	 * If we got here then we have to allocate an unmanaged one	 * This is not good.	 */	dev->unmanagedTempAllocations++;	return YMALLOC(dev->nDataBytesPerChunk);}static void yaffs_ReleaseTempBuffer(yaffs_Device * dev, __u8 * buffer,				    int lineNo){	int i;	for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {		if (dev->tempBuffer[i].buffer == buffer) {			dev->tempBuffer[i].line = 0;			return;		}	}	if (buffer) {		/* assume it is an unmanaged one. */		T(YAFFS_TRACE_BUFFERS,		  (TSTR("Releasing unmanaged temp buffer in line %d" TENDSTR),		   lineNo));		YFREE(buffer);		dev->unmanagedTempDeallocations++;	}}/* * Determine if we have a managed buffer. */int yaffs_IsManagedTempBuffer(yaffs_Device * dev, const __u8 * buffer){	int i;	for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {		if (dev->tempBuffer[i].buffer == buffer)			return 1;	}    for (i = 0; i < dev->nShortOpCaches; i++) {        if( dev->srCache[i].data == buffer )            return 1;    }    if (buffer == dev->checkpointBuffer)      return 1;    T(YAFFS_TRACE_ALWAYS,	  (TSTR("yaffs: unmaged buffer detected.\n" TENDSTR)));    return 0;}/* * Chunk bitmap manipulations */static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device * dev, int blk){	if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {		T(YAFFS_TRACE_ERROR,		  (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),		   blk));		YBUG();	}	return dev->chunkBits +	    (dev->chunkBitmapStride * (blk - dev->internalStartBlock));}static Y_INLINE void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk){	if(blk < dev->internalStartBlock || blk > dev->internalEndBlock ||	   chunk < 0 || chunk >= dev->nChunksPerBlock) {	   T(YAFFS_TRACE_ERROR,	    (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),blk,chunk));	    YBUG();	}}static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device * dev, int blk){	__u8 *blkBits = yaffs_BlockBits(dev, blk);	memset(blkBits, 0, dev->chunkBitmapStride);}static Y_INLINE void yaffs_ClearChunkBit(yaffs_Device * dev, int blk, int chunk){	__u8 *blkBits = yaffs_BlockBits(dev, blk);	yaffs_VerifyChunkBitId(dev,blk,chunk);	blkBits[chunk / 8] &= ~(1 << (chunk & 7));}static Y_INLINE void yaffs_SetChunkBit(yaffs_Device * dev, int blk, int chunk){	__u8 *blkBits = yaffs_BlockBits(dev, blk);		yaffs_VerifyChunkBitId(dev,blk,chunk);	blkBits[chunk / 8] |= (1 << (chunk & 7));}static Y_INLINE int yaffs_CheckChunkBit(yaffs_Device * dev, int blk, int chunk){	__u8 *blkBits = yaffs_BlockBits(dev, blk);	yaffs_VerifyChunkBitId(dev,blk,chunk);	return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;}static Y_INLINE int yaffs_StillSomeChunkBits(yaffs_Device * dev, int blk){	__u8 *blkBits = yaffs_BlockBits(dev, blk);	int i;	for (i = 0; i < dev->chunkBitmapStride; i++) {		if (*blkBits)			return 1;		blkBits++;	}	return 0;}static int yaffs_CountChunkBits(yaffs_Device * dev, int blk){	__u8 *blkBits = yaffs_BlockBits(dev, blk);	int i;	int n = 0;	for (i = 0; i < dev->chunkBitmapStride; i++) {		__u8 x = *blkBits;		while(x){			if(x & 1)				n++;			x >>=1;		}					blkBits++;	}	return n;}/*  * Verification code */ static int yaffs_SkipVerification(yaffs_Device *dev){	return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));}static int yaffs_SkipFullVerification(yaffs_Device *dev){	return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL));}static int yaffs_SkipNANDVerification(yaffs_Device *dev){	return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND));}static const char * blockStateName[] = {"Unknown","Needs scanning","Scanning","Empty","Allocating","Full","Dirty","Checkpoint","Collecting","Dead"};static void yaffs_VerifyBlock(yaffs_Device *dev,yaffs_BlockInfo *bi,int n){	int actuallyUsed;	int inUse;		if(yaffs_SkipVerification(dev))		return;			/* Report illegal runtime states */	if(bi->blockState <0 || bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES)		T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has undefined state %d"TENDSTR),n,bi->blockState));			switch(bi->blockState){	 case YAFFS_BLOCK_STATE_UNKNOWN:	 case YAFFS_BLOCK_STATE_SCANNING:	 case YAFFS_BLOCK_STATE_NEEDS_SCANNING:		T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has bad run-state %s"TENDSTR),		n,blockStateName[bi->blockState]));	}		/* Check pages in use and soft deletions are legal */		actuallyUsed = bi->pagesInUse - bi->softDeletions;		if(bi->pagesInUse < 0 || bi->pagesInUse > dev->nChunksPerBlock ||	   bi->softDeletions < 0 || bi->softDeletions > dev->nChunksPerBlock ||	   actuallyUsed < 0 || actuallyUsed > dev->nChunksPerBlock)		T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR),		n,bi->pagesInUse,bi->softDeletions));				/* Check chunk bitmap legal */	inUse = yaffs_CountChunkBits(dev,n);	if(inUse != bi->pagesInUse)		T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR),			n,bi->pagesInUse,inUse));		/* Check that the sequence number is valid.	 * Ten million is legal, but is very unlikely 	 */	if(dev->isYaffs2 && 	   (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || bi->blockState == YAFFS_BLOCK_STATE_FULL) &&	   (bi->sequenceNumber < YAFFS_LOWEST_SEQUENCE_NUMBER || bi->sequenceNumber > 10000000 ))		T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has suspect sequence number of %d"TENDSTR),		n,bi->sequenceNumber));		}static void yaffs_VerifyCollectedBlock(yaffs_Device *dev,yaffs_BlockInfo *bi,int n){	yaffs_VerifyBlock(dev,bi,n);		/* After collection the block should be in the erased state */	/* TODO: This will need to change if we do partial gc */		if(bi->blockState != YAFFS_BLOCK_STATE_EMPTY){		T(YAFFS_TRACE_ERROR,(TSTR("Block %d is in state %d after gc, should be erased"TENDSTR),			n,bi->blockState));	}}static void yaffs_VerifyBlocks(yaffs_Device *dev){	int i;	int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES];	int nIllegalBlockStates = 0;		if(yaffs_SkipVerification(dev))		return;	memset(nBlocksPerState,0,sizeof(nBlocksPerState));			for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++){		yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i);		yaffs_VerifyBlock(dev,bi,i);		if(bi->blockState >=0 && bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES)			nBlocksPerState[bi->blockState]++;		else			nIllegalBlockStates++;						}		T(YAFFS_TRACE_VERIFY,(TSTR(""TENDSTR)));	T(YAFFS_TRACE_VERIFY,(TSTR("Block summary"TENDSTR)));		T(YAFFS_TRACE_VERIFY,(TSTR("%d blocks have illegal states"TENDSTR),nIllegalBlockStates));	if(nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1)		T(YAFFS_TRACE_VERIFY,(TSTR("Too many allocating blocks"TENDSTR)));	for(i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)		T(YAFFS_TRACE_VERIFY,		  (TSTR("%s %d blocks"TENDSTR),		  blockStateName[i],nBlocksPerState[i]));		if(dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])		T(YAFFS_TRACE_VERIFY,		 (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR),		 dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]));		 	if(dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])		T(YAFFS_TRACE_VERIFY,		 (TSTR("Erased block count wrong dev %d count %d"TENDSTR),		 dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]));		 	if(nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1)		T(YAFFS_TRACE_VERIFY,		 (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR),		 nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING]));	T(YAFFS_TRACE_VERIFY,(TSTR(""TENDSTR)));}/* * Verify the object header. oh must be valid, but obj and tags may be NULL in which * case those tests will not be performed. */static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck){	if(yaffs_SkipVerification(obj->myDev))		return;			if(!(tags && obj && oh)){	 	T(YAFFS_TRACE_VERIFY,

⌨️ 快捷键说明

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