diff options
| author | kaloz <kaloz@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2008-06-02 08:22:56 +0000 | 
|---|---|---|
| committer | kaloz <kaloz@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2008-06-02 08:22:56 +0000 | 
| commit | 8540d5d19ebac6a3f30d82f36ff33f19d728f10b (patch) | |
| tree | a3141c916b391658ab197350ee398aace4ad9f35 /target/linux/generic-2.6/files-2.6.26/fs/yaffs2/yaffs_checkptrw.c | |
| parent | d2cb36d9c515ecd3f94864082cfe86f75796eeaf (diff) | |
add generic 2.6.26 patches/files
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@11323 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/generic-2.6/files-2.6.26/fs/yaffs2/yaffs_checkptrw.c')
| -rw-r--r-- | target/linux/generic-2.6/files-2.6.26/fs/yaffs2/yaffs_checkptrw.c | 404 | 
1 files changed, 404 insertions, 0 deletions
diff --git a/target/linux/generic-2.6/files-2.6.26/fs/yaffs2/yaffs_checkptrw.c b/target/linux/generic-2.6/files-2.6.26/fs/yaffs2/yaffs_checkptrw.c new file mode 100644 index 000000000..933a33fb8 --- /dev/null +++ b/target/linux/generic-2.6/files-2.6.26/fs/yaffs2/yaffs_checkptrw.c @@ -0,0 +1,404 @@ +/* + * 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_checkptrw_c_version = +    "$Id: yaffs_checkptrw.c,v 1.14 2007-05-15 20:07:40 charles Exp $"; + + +#include "yaffs_checkptrw.h" + + +static int yaffs_CheckpointSpaceOk(yaffs_Device *dev) +{ + +	int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks; + +	T(YAFFS_TRACE_CHECKPOINT, +		(TSTR("checkpt blocks available = %d" TENDSTR), +		blocksAvailable)); + + +	return (blocksAvailable <= 0) ? 0 : 1; +} + + +static int yaffs_CheckpointErase(yaffs_Device *dev) +{ + +	int i; + + +	if(!dev->eraseBlockInNAND) +		return 0; +	T(YAFFS_TRACE_CHECKPOINT,(TSTR("checking blocks %d to %d"TENDSTR), +		dev->internalStartBlock,dev->internalEndBlock)); + +	for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { +		yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i); +		if(bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT){ +			T(YAFFS_TRACE_CHECKPOINT,(TSTR("erasing checkpt block %d"TENDSTR),i)); +			if(dev->eraseBlockInNAND(dev,i- dev->blockOffset /* realign */)){ +				bi->blockState = YAFFS_BLOCK_STATE_EMPTY; +				dev->nErasedBlocks++; +				dev->nFreeChunks += dev->nChunksPerBlock; +			} +			else { +				dev->markNANDBlockBad(dev,i); +				bi->blockState = YAFFS_BLOCK_STATE_DEAD; +			} +		} +	} + +	dev->blocksInCheckpoint = 0; + +	return 1; +} + + +static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev) +{ +	int  i; +	int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks; +	T(YAFFS_TRACE_CHECKPOINT, +		(TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR), +		dev->nErasedBlocks,dev->nReservedBlocks,blocksAvailable,dev->checkpointNextBlock)); + +	if(dev->checkpointNextBlock >= 0 && +	   dev->checkpointNextBlock <= dev->internalEndBlock && +	   blocksAvailable > 0){ + +		for(i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++){ +			yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i); +			if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY){ +				dev->checkpointNextBlock = i + 1; +				dev->checkpointCurrentBlock = i; +				T(YAFFS_TRACE_CHECKPOINT,(TSTR("allocating checkpt block %d"TENDSTR),i)); +				return; +			} +		} +	} +	T(YAFFS_TRACE_CHECKPOINT,(TSTR("out of checkpt blocks"TENDSTR))); + +	dev->checkpointNextBlock = -1; +	dev->checkpointCurrentBlock = -1; +} + +static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev) +{ +	int  i; +	yaffs_ExtendedTags tags; + +	T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: start:  blocks %d next %d" TENDSTR), +		dev->blocksInCheckpoint, dev->checkpointNextBlock)); + +	if(dev->blocksInCheckpoint < dev->checkpointMaxBlocks) +		for(i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++){ +			int chunk = i * dev->nChunksPerBlock; +			int realignedChunk = chunk - dev->chunkOffset; + +			dev->readChunkWithTagsFromNAND(dev,realignedChunk,NULL,&tags); +			T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR), +				i, tags.objectId,tags.sequenceNumber,tags.eccResult)); + +			if(tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA){ +				/* Right kind of block */ +				dev->checkpointNextBlock = tags.objectId; +				dev->checkpointCurrentBlock = i; +				dev->checkpointBlockList[dev->blocksInCheckpoint] = i; +				dev->blocksInCheckpoint++; +				T(YAFFS_TRACE_CHECKPOINT,(TSTR("found checkpt block %d"TENDSTR),i)); +				return; +			} +		} + +	T(YAFFS_TRACE_CHECKPOINT,(TSTR("found no more checkpt blocks"TENDSTR))); + +	dev->checkpointNextBlock = -1; +	dev->checkpointCurrentBlock = -1; +} + + +int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting) +{ + +	/* Got the functions we need? */ +	if (!dev->writeChunkWithTagsToNAND || +	    !dev->readChunkWithTagsFromNAND || +	    !dev->eraseBlockInNAND || +	    !dev->markNANDBlockBad) +		return 0; + +	if(forWriting && !yaffs_CheckpointSpaceOk(dev)) +		return 0; + +	if(!dev->checkpointBuffer) +		dev->checkpointBuffer = YMALLOC_DMA(dev->nDataBytesPerChunk); +	if(!dev->checkpointBuffer) +		return 0; + + +	dev->checkpointPageSequence = 0; + +	dev->checkpointOpenForWrite = forWriting; + +	dev->checkpointByteCount = 0; +	dev->checkpointSum = 0; +	dev->checkpointXor = 0; +	dev->checkpointCurrentBlock = -1; +	dev->checkpointCurrentChunk = -1; +	dev->checkpointNextBlock = dev->internalStartBlock; + +	/* Erase all the blocks in the checkpoint area */ +	if(forWriting){ +		memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk); +		dev->checkpointByteOffset = 0; +		return yaffs_CheckpointErase(dev); + + +	} else { +		int i; +		/* Set to a value that will kick off a read */ +		dev->checkpointByteOffset = dev->nDataBytesPerChunk; +		/* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully) +		 * going to be way more than we need */ +		dev->blocksInCheckpoint = 0; +		dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2; +		dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks); +		for(i = 0; i < dev->checkpointMaxBlocks; i++) +			dev->checkpointBlockList[i] = -1; +	} + +	return 1; +} + +int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum) +{ +	__u32 compositeSum; +	compositeSum =  (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF); +	*sum = compositeSum; +	return 1; +} + +static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev) +{ + +	int chunk; +	int realignedChunk; + +	yaffs_ExtendedTags tags; + +	if(dev->checkpointCurrentBlock < 0){ +		yaffs_CheckpointFindNextErasedBlock(dev); +		dev->checkpointCurrentChunk = 0; +	} + +	if(dev->checkpointCurrentBlock < 0) +		return 0; + +	tags.chunkDeleted = 0; +	tags.objectId = dev->checkpointNextBlock; /* Hint to next place to look */ +	tags.chunkId = dev->checkpointPageSequence + 1; +	tags.sequenceNumber =  YAFFS_SEQUENCE_CHECKPOINT_DATA; +	tags.byteCount = dev->nDataBytesPerChunk; +	if(dev->checkpointCurrentChunk == 0){ +		/* First chunk we write for the block? Set block state to +		   checkpoint */ +		yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,dev->checkpointCurrentBlock); +		bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT; +		dev->blocksInCheckpoint++; +	} + +	chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk; + + +	T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR), +		chunk, dev->checkpointCurrentBlock, dev->checkpointCurrentChunk,tags.objectId,tags.chunkId)); + +	realignedChunk = chunk - dev->chunkOffset; + +	dev->writeChunkWithTagsToNAND(dev,realignedChunk,dev->checkpointBuffer,&tags); +	dev->checkpointByteOffset = 0; +	dev->checkpointPageSequence++; +	dev->checkpointCurrentChunk++; +	if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock){ +		dev->checkpointCurrentChunk = 0; +		dev->checkpointCurrentBlock = -1; +	} +	memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk); + +	return 1; +} + + +int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes) +{ +	int i=0; +	int ok = 1; + + +	__u8 * dataBytes = (__u8 *)data; + + + +	if(!dev->checkpointBuffer) +		return 0; + +	if(!dev->checkpointOpenForWrite) +		return -1; + +	while(i < nBytes && ok) { + + + +		dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes ; +		dev->checkpointSum += *dataBytes; +		dev->checkpointXor ^= *dataBytes; + +		dev->checkpointByteOffset++; +		i++; +		dataBytes++; +		dev->checkpointByteCount++; + + +		if(dev->checkpointByteOffset < 0 || +		   dev->checkpointByteOffset >= dev->nDataBytesPerChunk) +			ok = yaffs_CheckpointFlushBuffer(dev); + +	} + +	return 	i; +} + +int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes) +{ +	int i=0; +	int ok = 1; +	yaffs_ExtendedTags tags; + + +	int chunk; +	int realignedChunk; + +	__u8 *dataBytes = (__u8 *)data; + +	if(!dev->checkpointBuffer) +		return 0; + +	if(dev->checkpointOpenForWrite) +		return -1; + +	while(i < nBytes && ok) { + + +		if(dev->checkpointByteOffset < 0 || +		   dev->checkpointByteOffset >= dev->nDataBytesPerChunk) { + +		   	if(dev->checkpointCurrentBlock < 0){ +				yaffs_CheckpointFindNextCheckpointBlock(dev); +				dev->checkpointCurrentChunk = 0; +			} + +			if(dev->checkpointCurrentBlock < 0) +				ok = 0; +			else { + +				chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + +				          dev->checkpointCurrentChunk; + +				realignedChunk = chunk - dev->chunkOffset; + +	   			/* read in the next chunk */ +	   			/* printf("read checkpoint page %d\n",dev->checkpointPage); */ +				dev->readChunkWithTagsFromNAND(dev, realignedChunk, +							       dev->checkpointBuffer, +							      &tags); + +				if(tags.chunkId != (dev->checkpointPageSequence + 1) || +				   tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA) +				   ok = 0; + +				dev->checkpointByteOffset = 0; +				dev->checkpointPageSequence++; +				dev->checkpointCurrentChunk++; + +				if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock) +					dev->checkpointCurrentBlock = -1; +			} +		} + +		if(ok){ +			*dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset]; +			dev->checkpointSum += *dataBytes; +			dev->checkpointXor ^= *dataBytes; +			dev->checkpointByteOffset++; +			i++; +			dataBytes++; +			dev->checkpointByteCount++; +		} +	} + +	return 	i; +} + +int yaffs_CheckpointClose(yaffs_Device *dev) +{ + +	if(dev->checkpointOpenForWrite){ +		if(dev->checkpointByteOffset != 0) +			yaffs_CheckpointFlushBuffer(dev); +	} else { +		int i; +		for(i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++){ +			yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,dev->checkpointBlockList[i]); +			if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY) +				bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT; +			else { +				// Todo this looks odd... +			} +		} +		YFREE(dev->checkpointBlockList); +		dev->checkpointBlockList = NULL; +	} + +	dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock; +	dev->nErasedBlocks -= dev->blocksInCheckpoint; + + +	T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint byte count %d" TENDSTR), +			dev->checkpointByteCount)); + +	if(dev->checkpointBuffer){ +		/* free the buffer */ +		YFREE(dev->checkpointBuffer); +		dev->checkpointBuffer = NULL; +		return 1; +	} +	else +		return 0; + +} + +int yaffs_CheckpointInvalidateStream(yaffs_Device *dev) +{ +	/* Erase the first checksum block */ + +	T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint invalidate"TENDSTR))); + +	if(!yaffs_CheckpointSpaceOk(dev)) +		return 0; + +	return yaffs_CheckpointErase(dev); +} + + +  | 
