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

📄 yaffs_guts.c

📁 yaffs2设备驱动
💻 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.1.1.1 2008/03/28 04:29:21 jlwei Exp $";#include "yportenv.h"#include "yaffsinterface.h"#include "yaffs_guts.h"#include "yaffs_tagsvalidity.h"#include "yaffs_tagscompat.h"#ifndef CONFIG_YAFFS_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);#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);/* 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 __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_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);	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);	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);	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;}/* *  Simple hash function. Needs to have a reasonable spread */ static Y_INLINE int yaffs_HashFunction(int n){	n = abs(n);	return (n % YAFFS_NOBJECT_BUCKETS);}/* * Access functions to useful fake objects */ yaffs_Object *yaffs_Root(yaffs_Device * dev){	return dev->rootDir;}yaffs_Object *yaffs_LostNFound(yaffs_Device * dev){	return dev->lostNFoundDir;}/* *  Erased NAND checking functions */ int yaffs_CheckFF(__u8 * buffer, int nBytes){	/* Horrible, slow implementation */	while (nBytes--) {		if (*buffer != 0xFF)			return 0;		buffer++;	}	return 1;}static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,				  int chunkInNAND){	int retval = YAFFS_OK;	__u8 *data = yaffs_GetTempBuffer(dev, __LINE__);	yaffs_ExtendedTags tags;	int result;	result = yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags);		if(tags.eccResult > YAFFS_ECC_RESULT_NO_ERROR)		retval = YAFFS_FAIL;			if (!yaffs_CheckFF(data, dev->nDataBytesPerChunk) || tags.chunkUsed) {		T(YAFFS_TRACE_NANDACCESS,		  (TSTR("Chunk %d not erased" TENDSTR), chunkInNAND));		retval = YAFFS_FAIL;	}	yaffs_ReleaseTempBuffer(dev, data, __LINE__);	return retval;}static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,					     const __u8 * data,					     yaffs_ExtendedTags * tags,					     int useReserve){	int chunk;	int writeOk = 0;	int erasedOk = 1;	int attempts = 0;	yaffs_BlockInfo *bi;		yaffs_InvalidateCheckpoint(dev);	do {		chunk = yaffs_AllocateChunk(dev, useReserve,&bi);		if (chunk >= 0) {			/* First check this chunk is erased, if it needs checking.			 * The checking policy (unless forced always on) is as follows:			 * Check the first page we try to write in a block.			 * - If the check passes then we don't need to check any more.			 * - If the check fails, we check again...			 * If the block has been erased, we don't need to check.			 *			 * However, if the block has been prioritised for gc, then			 * we think there might be something odd about this block			 * and stop using it.			 *			 * Rationale:			 * We should only ever see chunks that have not been erased			 * if there was a partially written chunk due to power loss			 * This checking policy should catch that case with very			 * few checks and thus save a lot of checks that are most likely not			 * needed.			 */			 			 if(bi->gcPrioritise){			 		yaffs_DeleteChunk(dev, chunk, 1, __LINE__);			} else {#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED				bi->skipErasedCheck = 0;#endif				if(!bi->skipErasedCheck){					erasedOk = yaffs_CheckChunkErased(dev, chunk);					if(erasedOk && !bi->gcPrioritise)						bi->skipErasedCheck = 1;				}				if (!erasedOk) {					T(YAFFS_TRACE_ERROR,					  (TSTR					   ("**>> yaffs chunk %d was not erased"					    TENDSTR), chunk));				} else {					writeOk =					    yaffs_WriteChunkWithTagsToNAND(dev, chunk,									   data, tags);				}							attempts++;				if (writeOk) {					/*					 *  Copy the data into the robustification buffer.					 *  NB We do this at the end to prevent duplicates in the case of a write error.					 *  Todo					 */					yaffs_HandleWriteChunkOk(dev, chunk, data, tags);								} else {					/* The erased check or write failed */					yaffs_HandleWriteChunkError(dev, chunk, erasedOk);				}			}		}	} while (chunk >= 0 && !writeOk);	if (attempts > 1) {		T(YAFFS_TRACE_ERROR,		  (TSTR("**>> yaffs write required %d attempts" TENDSTR),		   attempts));		dev->nRetriedWrites += (attempts - 1);	}	return chunk;}/* * Block retiring for handling a broken block. */ static void yaffs_RetireBlock(yaffs_Device * dev, int blockInNAND){	yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);	yaffs_InvalidateCheckpoint(dev);		yaffs_MarkBlockBad(dev, blockInNAND);	bi->blockState = YAFFS_BLOCK_STATE_DEAD;	bi->gcPrioritise = 0;	bi->needsRetiring = 0;	dev->nRetiredBlocks++;}/* * Functions for robustisizing TODO * */ 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){}void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi){	if(!bi->gcPrioritise){		bi->gcPrioritise = 1;		dev->hasPendingPrioritisedGCs = 1;		bi->chunkErrorStrikes ++;				if(bi->chunkErrorStrikes > 3){			bi->needsRetiring = 1; /* Too many stikes, so retire this */			T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR)));		}			}}static void yaffs_ReportOddballBlocks(yaffs_Device *dev){	int i;			for(i = dev->internalStartBlock; i <= dev->internalEndBlock && (yaffs_traceMask & YAFFS_TRACE_BAD_BLOCKS); i++){		yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i);		if(bi->needsRetiring || bi->gcPrioritise)			T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("yaffs block %d%s%s" TENDSTR),				i,				bi->needsRetiring ? " needs retiring" : "",				bi->gcPrioritise ?  " gc prioritised" : ""));			}

⌨️ 快捷键说明

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