2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
4 * Copyright (C) 2002-2007 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.
18 const char *yaffs_checkptrw_c_version
=
19 "$Id: yaffs_checkptrw.c,v 1.14 2007/05/15 20:07:40 charles Exp $";
22 #include "yaffs_checkptrw.h"
25 static int yaffs_CheckpointSpaceOk(yaffs_Device
*dev
)
28 int blocksAvailable
= dev
->nErasedBlocks
- dev
->nReservedBlocks
;
30 T(YAFFS_TRACE_CHECKPOINT
,
31 (TSTR("checkpt blocks available = %d" TENDSTR
),
35 return (blocksAvailable
<= 0) ? 0 : 1;
39 static int yaffs_CheckpointErase(yaffs_Device
*dev
)
45 if(!dev
->eraseBlockInNAND
)
47 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("checking blocks %d to %d"TENDSTR
),
48 dev
->internalStartBlock
,dev
->internalEndBlock
));
50 for(i
= dev
->internalStartBlock
; i
<= dev
->internalEndBlock
; i
++) {
51 yaffs_BlockInfo
*bi
= yaffs_GetBlockInfo(dev
,i
);
52 if(bi
->blockState
== YAFFS_BLOCK_STATE_CHECKPOINT
){
53 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("erasing checkpt block %d"TENDSTR
),i
));
54 if(dev
->eraseBlockInNAND(dev
,i
- dev
->blockOffset
/* realign */)){
55 bi
->blockState
= YAFFS_BLOCK_STATE_EMPTY
;
57 dev
->nFreeChunks
+= dev
->nChunksPerBlock
;
60 dev
->markNANDBlockBad(dev
,i
);
61 bi
->blockState
= YAFFS_BLOCK_STATE_DEAD
;
66 dev
->blocksInCheckpoint
= 0;
72 static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device
*dev
)
75 int blocksAvailable
= dev
->nErasedBlocks
- dev
->nReservedBlocks
;
76 T(YAFFS_TRACE_CHECKPOINT
,
77 (TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR
),
78 dev
->nErasedBlocks
,dev
->nReservedBlocks
,blocksAvailable
,dev
->checkpointNextBlock
));
80 if(dev
->checkpointNextBlock
>= 0 &&
81 dev
->checkpointNextBlock
<= dev
->internalEndBlock
&&
84 for(i
= dev
->checkpointNextBlock
; i
<= dev
->internalEndBlock
; i
++){
85 yaffs_BlockInfo
*bi
= yaffs_GetBlockInfo(dev
,i
);
86 if(bi
->blockState
== YAFFS_BLOCK_STATE_EMPTY
){
87 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 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR
),
106 dev
->blocksInCheckpoint
, dev
->checkpointNextBlock
));
108 if(dev
->blocksInCheckpoint
< dev
->checkpointMaxBlocks
)
109 for(i
= dev
->checkpointNextBlock
; i
<= dev
->internalEndBlock
; i
++){
110 int chunk
= i
* dev
->nChunksPerBlock
;
111 int realignedChunk
= chunk
- dev
->chunkOffset
;
113 dev
->readChunkWithTagsFromNAND(dev
,realignedChunk
,NULL
,&tags
);
114 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR
),
115 i
, tags
.objectId
,tags
.sequenceNumber
,tags
.eccResult
));
117 if(tags
.sequenceNumber
== YAFFS_SEQUENCE_CHECKPOINT_DATA
){
118 /* Right kind of block */
119 dev
->checkpointNextBlock
= tags
.objectId
;
120 dev
->checkpointCurrentBlock
= i
;
121 dev
->checkpointBlockList
[dev
->blocksInCheckpoint
] = i
;
122 dev
->blocksInCheckpoint
++;
123 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("found checkpt block %d"TENDSTR
),i
));
128 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("found no more checkpt blocks"TENDSTR
)));
130 dev
->checkpointNextBlock
= -1;
131 dev
->checkpointCurrentBlock
= -1;
135 int yaffs_CheckpointOpen(yaffs_Device
*dev
, int forWriting
)
138 /* Got the functions we need? */
139 if (!dev
->writeChunkWithTagsToNAND
||
140 !dev
->readChunkWithTagsFromNAND
||
141 !dev
->eraseBlockInNAND
||
142 !dev
->markNANDBlockBad
)
145 if(forWriting
&& !yaffs_CheckpointSpaceOk(dev
))
148 if(!dev
->checkpointBuffer
)
149 dev
->checkpointBuffer
= YMALLOC_DMA(dev
->nDataBytesPerChunk
);
150 if(!dev
->checkpointBuffer
)
154 dev
->checkpointPageSequence
= 0;
156 dev
->checkpointOpenForWrite
= forWriting
;
158 dev
->checkpointByteCount
= 0;
159 dev
->checkpointSum
= 0;
160 dev
->checkpointXor
= 0;
161 dev
->checkpointCurrentBlock
= -1;
162 dev
->checkpointCurrentChunk
= -1;
163 dev
->checkpointNextBlock
= dev
->internalStartBlock
;
165 /* Erase all the blocks in the checkpoint area */
167 memset(dev
->checkpointBuffer
,0,dev
->nDataBytesPerChunk
);
168 dev
->checkpointByteOffset
= 0;
169 return yaffs_CheckpointErase(dev
);
174 /* Set to a value that will kick off a read */
175 dev
->checkpointByteOffset
= dev
->nDataBytesPerChunk
;
176 /* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully)
177 * going to be way more than we need */
178 dev
->blocksInCheckpoint
= 0;
179 dev
->checkpointMaxBlocks
= (dev
->internalEndBlock
- dev
->internalStartBlock
)/16 + 2;
180 dev
->checkpointBlockList
= YMALLOC(sizeof(int) * dev
->checkpointMaxBlocks
);
181 for(i
= 0; i
< dev
->checkpointMaxBlocks
; i
++)
182 dev
->checkpointBlockList
[i
] = -1;
188 int yaffs_GetCheckpointSum(yaffs_Device
*dev
, __u32
*sum
)
191 compositeSum
= (dev
->checkpointSum
<< 8) | (dev
->checkpointXor
& 0xFF);
196 static int yaffs_CheckpointFlushBuffer(yaffs_Device
*dev
)
202 yaffs_ExtendedTags tags
;
204 if(dev
->checkpointCurrentBlock
< 0){
205 yaffs_CheckpointFindNextErasedBlock(dev
);
206 dev
->checkpointCurrentChunk
= 0;
209 if(dev
->checkpointCurrentBlock
< 0)
212 tags
.chunkDeleted
= 0;
213 tags
.objectId
= dev
->checkpointNextBlock
; /* Hint to next place to look */
214 tags
.chunkId
= dev
->checkpointPageSequence
+ 1;
215 tags
.sequenceNumber
= YAFFS_SEQUENCE_CHECKPOINT_DATA
;
216 tags
.byteCount
= dev
->nDataBytesPerChunk
;
217 if(dev
->checkpointCurrentChunk
== 0){
218 /* First chunk we write for the block? Set block state to
220 yaffs_BlockInfo
*bi
= yaffs_GetBlockInfo(dev
,dev
->checkpointCurrentBlock
);
221 bi
->blockState
= YAFFS_BLOCK_STATE_CHECKPOINT
;
222 dev
->blocksInCheckpoint
++;
225 chunk
= dev
->checkpointCurrentBlock
* dev
->nChunksPerBlock
+ dev
->checkpointCurrentChunk
;
228 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR
),
229 chunk
, dev
->checkpointCurrentBlock
, dev
->checkpointCurrentChunk
,tags
.objectId
,tags
.chunkId
));
231 realignedChunk
= chunk
- dev
->chunkOffset
;
233 dev
->writeChunkWithTagsToNAND(dev
,realignedChunk
,dev
->checkpointBuffer
,&tags
);
234 dev
->checkpointByteOffset
= 0;
235 dev
->checkpointPageSequence
++;
236 dev
->checkpointCurrentChunk
++;
237 if(dev
->checkpointCurrentChunk
>= dev
->nChunksPerBlock
){
238 dev
->checkpointCurrentChunk
= 0;
239 dev
->checkpointCurrentBlock
= -1;
241 memset(dev
->checkpointBuffer
,0,dev
->nDataBytesPerChunk
);
247 int yaffs_CheckpointWrite(yaffs_Device
*dev
,const void *data
, int nBytes
)
253 __u8
* dataBytes
= (__u8
*)data
;
257 if(!dev
->checkpointBuffer
)
260 if(!dev
->checkpointOpenForWrite
)
263 while(i
< nBytes
&& ok
) {
267 dev
->checkpointBuffer
[dev
->checkpointByteOffset
] = *dataBytes
;
268 dev
->checkpointSum
+= *dataBytes
;
269 dev
->checkpointXor
^= *dataBytes
;
271 dev
->checkpointByteOffset
++;
274 dev
->checkpointByteCount
++;
277 if(dev
->checkpointByteOffset
< 0 ||
278 dev
->checkpointByteOffset
>= dev
->nDataBytesPerChunk
)
279 ok
= yaffs_CheckpointFlushBuffer(dev
);
286 int yaffs_CheckpointRead(yaffs_Device
*dev
, void *data
, int nBytes
)
290 yaffs_ExtendedTags tags
;
296 __u8
*dataBytes
= (__u8
*)data
;
298 if(!dev
->checkpointBuffer
)
301 if(dev
->checkpointOpenForWrite
)
304 while(i
< nBytes
&& ok
) {
307 if(dev
->checkpointByteOffset
< 0 ||
308 dev
->checkpointByteOffset
>= dev
->nDataBytesPerChunk
) {
310 if(dev
->checkpointCurrentBlock
< 0){
311 yaffs_CheckpointFindNextCheckpointBlock(dev
);
312 dev
->checkpointCurrentChunk
= 0;
315 if(dev
->checkpointCurrentBlock
< 0)
319 chunk
= dev
->checkpointCurrentBlock
* dev
->nChunksPerBlock
+
320 dev
->checkpointCurrentChunk
;
322 realignedChunk
= chunk
- dev
->chunkOffset
;
324 /* read in the next chunk */
325 /* printf("read checkpoint page %d\n",dev->checkpointPage); */
326 dev
->readChunkWithTagsFromNAND(dev
, realignedChunk
,
327 dev
->checkpointBuffer
,
330 if(tags
.chunkId
!= (dev
->checkpointPageSequence
+ 1) ||
331 tags
.sequenceNumber
!= YAFFS_SEQUENCE_CHECKPOINT_DATA
)
334 dev
->checkpointByteOffset
= 0;
335 dev
->checkpointPageSequence
++;
336 dev
->checkpointCurrentChunk
++;
338 if(dev
->checkpointCurrentChunk
>= dev
->nChunksPerBlock
)
339 dev
->checkpointCurrentBlock
= -1;
344 *dataBytes
= dev
->checkpointBuffer
[dev
->checkpointByteOffset
];
345 dev
->checkpointSum
+= *dataBytes
;
346 dev
->checkpointXor
^= *dataBytes
;
347 dev
->checkpointByteOffset
++;
350 dev
->checkpointByteCount
++;
357 int yaffs_CheckpointClose(yaffs_Device
*dev
)
360 if(dev
->checkpointOpenForWrite
){
361 if(dev
->checkpointByteOffset
!= 0)
362 yaffs_CheckpointFlushBuffer(dev
);
365 for(i
= 0; i
< dev
->blocksInCheckpoint
&& dev
->checkpointBlockList
[i
] >= 0; i
++){
366 yaffs_BlockInfo
*bi
= yaffs_GetBlockInfo(dev
,dev
->checkpointBlockList
[i
]);
367 if(bi
->blockState
== YAFFS_BLOCK_STATE_EMPTY
)
368 bi
->blockState
= YAFFS_BLOCK_STATE_CHECKPOINT
;
370 // Todo this looks odd...
373 YFREE(dev
->checkpointBlockList
);
374 dev
->checkpointBlockList
= NULL
;
377 dev
->nFreeChunks
-= dev
->blocksInCheckpoint
* dev
->nChunksPerBlock
;
378 dev
->nErasedBlocks
-= dev
->blocksInCheckpoint
;
381 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("checkpoint byte count %d" TENDSTR
),
382 dev
->checkpointByteCount
));
384 if(dev
->checkpointBuffer
){
385 /* free the buffer */
386 YFREE(dev
->checkpointBuffer
);
387 dev
->checkpointBuffer
= NULL
;
395 int yaffs_CheckpointInvalidateStream(yaffs_Device
*dev
)
397 /* Erase the first checksum block */
399 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("checkpoint invalidate"TENDSTR
)));
401 if(!yaffs_CheckpointSpaceOk(dev
))
404 return yaffs_CheckpointErase(dev
);