2 * YAFFS: Yet another FFS. A NAND-flash specific file system.
4 * Copyright (C) 2002 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
7 * Created by Charles Manning <charles@aleph1.co.uk>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
15 const char *yaffs_checkptrw_c_version =
16 "$Id: yaffs_checkptrw.c,v 1.2 2006-05-17 09:31:07 charles Exp $";
19 #include "yaffs_checkptrw.h"
22 static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
25 int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
27 if(blocksAvailable < 0)
30 T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpt blocks available" TENDSTR)));
33 if(blocksAvailable <= 0)
41 static int yaffs_CheckpointErase(yaffs_Device *dev)
47 if(!dev->eraseBlockInNAND)
49 T(YAFFS_TRACE_CHECKPOINT,(TSTR("checking blocks %d to %d"TENDSTR),
50 dev->startBlock,dev->endBlock));
52 for(i = dev->startBlock; i <= dev->endBlock; i++) {
53 yaffs_BlockInfo *bi = &dev->blockInfo[i];
54 if(bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT){
55 T(YAFFS_TRACE_CHECKPOINT,(TSTR("erasing checkpt block %d"TENDSTR),i));
56 if(dev->eraseBlockInNAND(dev,i)){
57 bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
59 dev->nFreeChunks += dev->nChunksPerBlock;
62 dev->markNANDBlockBad(dev,i);
63 bi->blockState = YAFFS_BLOCK_STATE_DEAD;
68 dev->blocksInCheckpoint = 0;
74 static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev)
77 int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
79 if(dev->checkpointNextBlock >= 0 &&
80 dev->checkpointNextBlock <= dev->endBlock &&
83 for(i = dev->checkpointNextBlock; i <= dev->endBlock; i++){
84 yaffs_BlockInfo *bi = &dev->blockInfo[i];
85 if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY){
86 dev->checkpointNextBlock = i + 1;
88 dev->checkpointCurrentBlock = i;
89 T(YAFFS_TRACE_CHECKPOINT,(TSTR("allocating checkpt block %d"TENDSTR),i));
94 T(YAFFS_TRACE_CHECKPOINT,(TSTR("out of checkpt blocks"TENDSTR)));
96 dev->checkpointNextBlock = -1;
97 dev->checkpointCurrentBlock = -1;
100 static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
103 yaffs_ExtendedTags tags;
105 if(dev->blocksInCheckpoint < dev->checkpointMaxBlocks)
106 for(i = dev->checkpointNextBlock; i <= dev->endBlock; i++){
107 int chunk = i * dev->nChunksPerBlock;
109 dev->readChunkWithTagsFromNAND(dev,chunk,NULL,&tags);
111 if(tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA){
112 /* Right kind of block */
113 dev->checkpointNextBlock = tags.objectId;
114 dev->checkpointCurrentBlock = i;
115 dev->checkpointBlockList[dev->blocksInCheckpoint] = i;
116 dev->blocksInCheckpoint++;
117 T(YAFFS_TRACE_CHECKPOINT,(TSTR("found checkpt block %d"TENDSTR),i));
122 T(YAFFS_TRACE_CHECKPOINT,(TSTR("found no more checkpt blocks"TENDSTR)));
124 dev->checkpointNextBlock = -1;
125 dev->checkpointCurrentBlock = -1;
129 int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
132 /* Got the functions we need? */
133 if (!dev->writeChunkWithTagsToNAND ||
134 !dev->readChunkWithTagsFromNAND ||
135 !dev->eraseBlockInNAND ||
136 !dev->markNANDBlockBad)
139 if(forWriting && !yaffs_CheckpointSpaceOk(dev))
142 if(!dev->checkpointBuffer)
143 dev->checkpointBuffer = YMALLOC(dev->nBytesPerChunk);
144 if(!dev->checkpointBuffer)
148 dev->checkpointPageSequence = 0;
150 dev->checkpointOpenForWrite = forWriting;
152 dev->checkpointByteCount = 0;
153 dev->checkpointCurrentBlock = -1;
154 dev->checkpointCurrentChunk = -1;
155 dev->checkpointNextBlock = dev->startBlock;
157 /* Erase all the blocks in the checkpoint area */
159 memset(dev->checkpointBuffer,0,dev->nBytesPerChunk);
160 dev->checkpointByteOffset = 0;
161 return yaffs_CheckpointErase(dev);
166 /* Set to a value that will kick off a read */
167 dev->checkpointByteOffset = dev->nBytesPerChunk;
168 /* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully)
169 * going to be way more than we need */
170 dev->checkpointMaxBlocks = (dev->endBlock - dev->startBlock)/16 + 2;
171 dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks);
172 for(i = 0; i < dev->checkpointMaxBlocks; i++)
173 dev->checkpointBlockList[i] = -1;
179 static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)
184 yaffs_ExtendedTags tags;
186 if(dev->checkpointCurrentBlock < 0){
187 yaffs_CheckpointFindNextErasedBlock(dev);
188 dev->checkpointCurrentChunk = 0;
191 if(dev->checkpointCurrentBlock < 0)
194 tags.chunkDeleted = 0;
195 tags.objectId = dev->checkpointNextBlock; /* Hint to next place to look */
196 tags.chunkId = dev->checkpointPageSequence + 1;
197 tags.sequenceNumber = YAFFS_SEQUENCE_CHECKPOINT_DATA;
198 tags.byteCount = dev->nBytesPerChunk;
200 chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk;
202 dev->writeChunkWithTagsToNAND(dev,chunk,dev->checkpointBuffer,&tags);
203 dev->checkpointByteOffset = 0;
204 dev->checkpointPageSequence++;
205 dev->checkpointCurrentChunk++;
206 if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock){
207 dev->checkpointCurrentChunk = 0;
208 dev->checkpointCurrentBlock = -1;
210 memset(dev->checkpointBuffer,0,dev->nBytesPerChunk);
216 int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes)
222 __u8 * dataBytes = (__u8 *)data;
226 if(!dev->checkpointBuffer)
229 while(i < nBytes && ok) {
233 dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes ;
234 dev->checkpointByteOffset++;
237 dev->checkpointByteCount++;
240 if(dev->checkpointByteOffset < 0 ||
241 dev->checkpointByteOffset >= dev->nBytesPerChunk)
242 ok = yaffs_CheckpointFlushBuffer(dev);
249 int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
253 yaffs_ExtendedTags tags;
258 __u8 *dataBytes = (__u8 *)data;
260 if(!dev->checkpointBuffer)
263 while(i < nBytes && ok) {
266 if(dev->checkpointByteOffset < 0 ||
267 dev->checkpointByteOffset >= dev->nBytesPerChunk) {
269 if(dev->checkpointCurrentBlock < 0){
270 yaffs_CheckpointFindNextCheckpointBlock(dev);
271 dev->checkpointCurrentChunk = 0;
274 if(dev->checkpointCurrentBlock < 0)
278 chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock +
279 dev->checkpointCurrentChunk;
281 /* read in the next chunk */
282 /* printf("read checkpoint page %d\n",dev->checkpointPage); */
283 dev->readChunkWithTagsFromNAND(dev, chunk,
284 dev->checkpointBuffer,
287 if(tags.chunkId != (dev->checkpointPageSequence + 1) ||
288 tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA)
291 dev->checkpointByteOffset = 0;
292 dev->checkpointPageSequence++;
293 dev->checkpointCurrentChunk++;
295 if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock)
296 dev->checkpointCurrentBlock = -1;
301 *dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset];
302 dev->checkpointByteOffset++;
305 dev->checkpointByteCount++;
312 int yaffs_CheckpointClose(yaffs_Device *dev)
315 if(dev->checkpointOpenForWrite){
316 if(dev->checkpointByteOffset != 0)
317 yaffs_CheckpointFlushBuffer(dev);
320 for(i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++){
321 yaffs_BlockInfo *bi = &dev->blockInfo[dev->checkpointBlockList[i]];
322 if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
323 bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
325 // Todo this looks odd...
328 YFREE(dev->checkpointBlockList);
329 dev->checkpointBlockList = NULL;
332 dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock;
333 dev->nErasedBlocks -= dev->blocksInCheckpoint;
336 T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint byte count %d" TENDSTR),
337 dev->checkpointByteCount));
339 if(dev->checkpointBuffer){
340 /* free the buffer */
341 YFREE(dev->checkpointBuffer);
342 dev->checkpointBuffer = NULL;
350 int yaffs_CheckpointInvalidateStream(yaffs_Device *dev)
352 /* Erase the first checksum block */
354 T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint invalidate"TENDSTR)));
356 if(!yaffs_CheckpointSpaceOk(dev))
359 return yaffs_CheckpointErase(dev);