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.
14 const char *yaffs_checkptrw_c_version
=
15 "$Id: yaffs_checkptrw.c,v 1.14 2007-05-15 20:07:40 charles Exp $";
18 #include "yaffs_checkptrw.h"
21 static int yaffs_CheckpointSpaceOk(yaffs_Device
*dev
)
24 int blocksAvailable
= dev
->nErasedBlocks
- dev
->nReservedBlocks
;
26 T(YAFFS_TRACE_CHECKPOINT
,
27 (TSTR("checkpt blocks available = %d" TENDSTR
),
31 return (blocksAvailable
<= 0) ? 0 : 1;
35 static int yaffs_CheckpointErase(yaffs_Device
*dev
)
41 if(!dev
->eraseBlockInNAND
)
43 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("checking blocks %d to %d"TENDSTR
),
44 dev
->internalStartBlock
,dev
->internalEndBlock
));
46 for(i
= dev
->internalStartBlock
; i
<= dev
->internalEndBlock
; i
++) {
47 yaffs_BlockInfo
*bi
= yaffs_GetBlockInfo(dev
,i
);
48 if(bi
->blockState
== YAFFS_BLOCK_STATE_CHECKPOINT
){
49 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("erasing checkpt block %d"TENDSTR
),i
));
50 if(dev
->eraseBlockInNAND(dev
,i
- dev
->blockOffset
/* realign */)){
51 bi
->blockState
= YAFFS_BLOCK_STATE_EMPTY
;
53 dev
->nFreeChunks
+= dev
->nChunksPerBlock
;
56 dev
->markNANDBlockBad(dev
,i
);
57 bi
->blockState
= YAFFS_BLOCK_STATE_DEAD
;
62 dev
->blocksInCheckpoint
= 0;
68 static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device
*dev
)
71 int blocksAvailable
= dev
->nErasedBlocks
- dev
->nReservedBlocks
;
72 T(YAFFS_TRACE_CHECKPOINT
,
73 (TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR
),
74 dev
->nErasedBlocks
,dev
->nReservedBlocks
,blocksAvailable
,dev
->checkpointNextBlock
));
76 if(dev
->checkpointNextBlock
>= 0 &&
77 dev
->checkpointNextBlock
<= dev
->internalEndBlock
&&
80 for(i
= dev
->checkpointNextBlock
; i
<= dev
->internalEndBlock
; i
++){
81 yaffs_BlockInfo
*bi
= yaffs_GetBlockInfo(dev
,i
);
82 if(bi
->blockState
== YAFFS_BLOCK_STATE_EMPTY
){
83 dev
->checkpointNextBlock
= i
+ 1;
84 dev
->checkpointCurrentBlock
= i
;
85 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("allocating checkpt block %d"TENDSTR
),i
));
90 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("out of checkpt blocks"TENDSTR
)));
92 dev
->checkpointNextBlock
= -1;
93 dev
->checkpointCurrentBlock
= -1;
96 static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device
*dev
)
99 yaffs_ExtendedTags tags
;
101 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR
),
102 dev
->blocksInCheckpoint
, dev
->checkpointNextBlock
));
104 if(dev
->blocksInCheckpoint
< dev
->checkpointMaxBlocks
)
105 for(i
= dev
->checkpointNextBlock
; i
<= dev
->internalEndBlock
; i
++){
106 int chunk
= i
* dev
->nChunksPerBlock
;
107 int realignedChunk
= chunk
- dev
->chunkOffset
;
109 dev
->readChunkWithTagsFromNAND(dev
,realignedChunk
,NULL
,&tags
);
110 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR
),
111 i
, tags
.objectId
,tags
.sequenceNumber
,tags
.eccResult
));
113 if(tags
.sequenceNumber
== YAFFS_SEQUENCE_CHECKPOINT_DATA
){
114 /* Right kind of block */
115 dev
->checkpointNextBlock
= tags
.objectId
;
116 dev
->checkpointCurrentBlock
= i
;
117 dev
->checkpointBlockList
[dev
->blocksInCheckpoint
] = i
;
118 dev
->blocksInCheckpoint
++;
119 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("found checkpt block %d"TENDSTR
),i
));
124 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("found no more checkpt blocks"TENDSTR
)));
126 dev
->checkpointNextBlock
= -1;
127 dev
->checkpointCurrentBlock
= -1;
131 int yaffs_CheckpointOpen(yaffs_Device
*dev
, int forWriting
)
134 /* Got the functions we need? */
135 if (!dev
->writeChunkWithTagsToNAND
||
136 !dev
->readChunkWithTagsFromNAND
||
137 !dev
->eraseBlockInNAND
||
138 !dev
->markNANDBlockBad
)
141 if(forWriting
&& !yaffs_CheckpointSpaceOk(dev
))
144 if(!dev
->checkpointBuffer
)
145 dev
->checkpointBuffer
= YMALLOC_DMA(dev
->nDataBytesPerChunk
);
146 if(!dev
->checkpointBuffer
)
150 dev
->checkpointPageSequence
= 0;
152 dev
->checkpointOpenForWrite
= forWriting
;
154 dev
->checkpointByteCount
= 0;
155 dev
->checkpointSum
= 0;
156 dev
->checkpointXor
= 0;
157 dev
->checkpointCurrentBlock
= -1;
158 dev
->checkpointCurrentChunk
= -1;
159 dev
->checkpointNextBlock
= dev
->internalStartBlock
;
161 /* Erase all the blocks in the checkpoint area */
163 memset(dev
->checkpointBuffer
,0,dev
->nDataBytesPerChunk
);
164 dev
->checkpointByteOffset
= 0;
165 return yaffs_CheckpointErase(dev
);
170 /* Set to a value that will kick off a read */
171 dev
->checkpointByteOffset
= dev
->nDataBytesPerChunk
;
172 /* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully)
173 * going to be way more than we need */
174 dev
->blocksInCheckpoint
= 0;
175 dev
->checkpointMaxBlocks
= (dev
->internalEndBlock
- dev
->internalStartBlock
)/16 + 2;
176 dev
->checkpointBlockList
= YMALLOC(sizeof(int) * dev
->checkpointMaxBlocks
);
177 for(i
= 0; i
< dev
->checkpointMaxBlocks
; i
++)
178 dev
->checkpointBlockList
[i
] = -1;
184 int yaffs_GetCheckpointSum(yaffs_Device
*dev
, __u32
*sum
)
187 compositeSum
= (dev
->checkpointSum
<< 8) | (dev
->checkpointXor
& 0xFF);
192 static int yaffs_CheckpointFlushBuffer(yaffs_Device
*dev
)
198 yaffs_ExtendedTags tags
;
200 if(dev
->checkpointCurrentBlock
< 0){
201 yaffs_CheckpointFindNextErasedBlock(dev
);
202 dev
->checkpointCurrentChunk
= 0;
205 if(dev
->checkpointCurrentBlock
< 0)
208 tags
.chunkDeleted
= 0;
209 tags
.objectId
= dev
->checkpointNextBlock
; /* Hint to next place to look */
210 tags
.chunkId
= dev
->checkpointPageSequence
+ 1;
211 tags
.sequenceNumber
= YAFFS_SEQUENCE_CHECKPOINT_DATA
;
212 tags
.byteCount
= dev
->nDataBytesPerChunk
;
213 if(dev
->checkpointCurrentChunk
== 0){
214 /* First chunk we write for the block? Set block state to
216 yaffs_BlockInfo
*bi
= yaffs_GetBlockInfo(dev
,dev
->checkpointCurrentBlock
);
217 bi
->blockState
= YAFFS_BLOCK_STATE_CHECKPOINT
;
218 dev
->blocksInCheckpoint
++;
221 chunk
= dev
->checkpointCurrentBlock
* dev
->nChunksPerBlock
+ dev
->checkpointCurrentChunk
;
224 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR
),
225 chunk
, dev
->checkpointCurrentBlock
, dev
->checkpointCurrentChunk
,tags
.objectId
,tags
.chunkId
));
227 realignedChunk
= chunk
- dev
->chunkOffset
;
229 dev
->writeChunkWithTagsToNAND(dev
,realignedChunk
,dev
->checkpointBuffer
,&tags
);
230 dev
->checkpointByteOffset
= 0;
231 dev
->checkpointPageSequence
++;
232 dev
->checkpointCurrentChunk
++;
233 if(dev
->checkpointCurrentChunk
>= dev
->nChunksPerBlock
){
234 dev
->checkpointCurrentChunk
= 0;
235 dev
->checkpointCurrentBlock
= -1;
237 memset(dev
->checkpointBuffer
,0,dev
->nDataBytesPerChunk
);
243 int yaffs_CheckpointWrite(yaffs_Device
*dev
,const void *data
, int nBytes
)
249 __u8
* dataBytes
= (__u8
*)data
;
253 if(!dev
->checkpointBuffer
)
256 if(!dev
->checkpointOpenForWrite
)
259 while(i
< nBytes
&& ok
) {
263 dev
->checkpointBuffer
[dev
->checkpointByteOffset
] = *dataBytes
;
264 dev
->checkpointSum
+= *dataBytes
;
265 dev
->checkpointXor
^= *dataBytes
;
267 dev
->checkpointByteOffset
++;
270 dev
->checkpointByteCount
++;
273 if(dev
->checkpointByteOffset
< 0 ||
274 dev
->checkpointByteOffset
>= dev
->nDataBytesPerChunk
)
275 ok
= yaffs_CheckpointFlushBuffer(dev
);
282 int yaffs_CheckpointRead(yaffs_Device
*dev
, void *data
, int nBytes
)
286 yaffs_ExtendedTags tags
;
292 __u8
*dataBytes
= (__u8
*)data
;
294 if(!dev
->checkpointBuffer
)
297 if(dev
->checkpointOpenForWrite
)
300 while(i
< nBytes
&& ok
) {
303 if(dev
->checkpointByteOffset
< 0 ||
304 dev
->checkpointByteOffset
>= dev
->nDataBytesPerChunk
) {
306 if(dev
->checkpointCurrentBlock
< 0){
307 yaffs_CheckpointFindNextCheckpointBlock(dev
);
308 dev
->checkpointCurrentChunk
= 0;
311 if(dev
->checkpointCurrentBlock
< 0)
315 chunk
= dev
->checkpointCurrentBlock
* dev
->nChunksPerBlock
+
316 dev
->checkpointCurrentChunk
;
318 realignedChunk
= chunk
- dev
->chunkOffset
;
320 /* read in the next chunk */
321 /* printf("read checkpoint page %d\n",dev->checkpointPage); */
322 dev
->readChunkWithTagsFromNAND(dev
, realignedChunk
,
323 dev
->checkpointBuffer
,
326 if(tags
.chunkId
!= (dev
->checkpointPageSequence
+ 1) ||
327 tags
.sequenceNumber
!= YAFFS_SEQUENCE_CHECKPOINT_DATA
)
330 dev
->checkpointByteOffset
= 0;
331 dev
->checkpointPageSequence
++;
332 dev
->checkpointCurrentChunk
++;
334 if(dev
->checkpointCurrentChunk
>= dev
->nChunksPerBlock
)
335 dev
->checkpointCurrentBlock
= -1;
340 *dataBytes
= dev
->checkpointBuffer
[dev
->checkpointByteOffset
];
341 dev
->checkpointSum
+= *dataBytes
;
342 dev
->checkpointXor
^= *dataBytes
;
343 dev
->checkpointByteOffset
++;
346 dev
->checkpointByteCount
++;
353 int yaffs_CheckpointClose(yaffs_Device
*dev
)
356 if(dev
->checkpointOpenForWrite
){
357 if(dev
->checkpointByteOffset
!= 0)
358 yaffs_CheckpointFlushBuffer(dev
);
361 for(i
= 0; i
< dev
->blocksInCheckpoint
&& dev
->checkpointBlockList
[i
] >= 0; i
++){
362 yaffs_BlockInfo
*bi
= yaffs_GetBlockInfo(dev
,dev
->checkpointBlockList
[i
]);
363 if(bi
->blockState
== YAFFS_BLOCK_STATE_EMPTY
)
364 bi
->blockState
= YAFFS_BLOCK_STATE_CHECKPOINT
;
366 // Todo this looks odd...
369 YFREE(dev
->checkpointBlockList
);
370 dev
->checkpointBlockList
= NULL
;
373 dev
->nFreeChunks
-= dev
->blocksInCheckpoint
* dev
->nChunksPerBlock
;
374 dev
->nErasedBlocks
-= dev
->blocksInCheckpoint
;
377 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("checkpoint byte count %d" TENDSTR
),
378 dev
->checkpointByteCount
));
380 if(dev
->checkpointBuffer
){
381 /* free the buffer */
382 YFREE(dev
->checkpointBuffer
);
383 dev
->checkpointBuffer
= NULL
;
391 int yaffs_CheckpointInvalidateStream(yaffs_Device
*dev
)
393 /* Erase the first checksum block */
395 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("checkpoint invalidate"TENDSTR
)));
397 if(!yaffs_CheckpointSpaceOk(dev
))
400 return yaffs_CheckpointErase(dev
);