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
=
17 #include "yaffs_checkptrw.h"
20 static int yaffs_CheckpointSpaceOk(yaffs_Device
*dev
)
23 int blocksAvailable
= dev
->nErasedBlocks
- dev
->nReservedBlocks
;
25 T(YAFFS_TRACE_CHECKPOINT
,
26 (TSTR("checkpt blocks available = %d" TENDSTR
),
30 return (blocksAvailable
<= 0) ? 0 : 1;
34 static int yaffs_CheckpointErase(yaffs_Device
*dev
)
40 if(!dev
->eraseBlockInNAND
)
42 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("checking blocks %d to %d"TENDSTR
),
43 dev
->internalStartBlock
,dev
->internalEndBlock
));
45 for(i
= dev
->internalStartBlock
; i
<= dev
->internalEndBlock
; i
++) {
46 yaffs_BlockInfo
*bi
= yaffs_GetBlockInfo(dev
,i
);
47 if(bi
->blockState
== YAFFS_BLOCK_STATE_CHECKPOINT
){
48 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("erasing checkpt block %d"TENDSTR
),i
));
49 if(dev
->eraseBlockInNAND(dev
,i
- dev
->blockOffset
/* realign */)){
50 bi
->blockState
= YAFFS_BLOCK_STATE_EMPTY
;
52 dev
->nFreeChunks
+= dev
->nChunksPerBlock
;
55 dev
->markNANDBlockBad(dev
,i
);
56 bi
->blockState
= YAFFS_BLOCK_STATE_DEAD
;
61 dev
->blocksInCheckpoint
= 0;
67 static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device
*dev
)
70 int blocksAvailable
= dev
->nErasedBlocks
- dev
->nReservedBlocks
;
71 T(YAFFS_TRACE_CHECKPOINT
,
72 (TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR
),
73 dev
->nErasedBlocks
,dev
->nReservedBlocks
,blocksAvailable
,dev
->checkpointNextBlock
));
75 if(dev
->checkpointNextBlock
>= 0 &&
76 dev
->checkpointNextBlock
<= dev
->internalEndBlock
&&
79 for(i
= dev
->checkpointNextBlock
; i
<= dev
->internalEndBlock
; i
++){
80 yaffs_BlockInfo
*bi
= yaffs_GetBlockInfo(dev
,i
);
81 if(bi
->blockState
== YAFFS_BLOCK_STATE_EMPTY
){
82 dev
->checkpointNextBlock
= i
+ 1;
83 dev
->checkpointCurrentBlock
= i
;
84 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("allocating checkpt block %d"TENDSTR
),i
));
89 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("out of checkpt blocks"TENDSTR
)));
91 dev
->checkpointNextBlock
= -1;
92 dev
->checkpointCurrentBlock
= -1;
95 static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device
*dev
)
98 yaffs_ExtendedTags tags
;
100 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR
),
101 dev
->blocksInCheckpoint
, dev
->checkpointNextBlock
));
103 if(dev
->blocksInCheckpoint
< dev
->checkpointMaxBlocks
)
104 for(i
= dev
->checkpointNextBlock
; i
<= dev
->internalEndBlock
; i
++){
105 int chunk
= i
* dev
->nChunksPerBlock
;
106 int realignedChunk
= chunk
- dev
->chunkOffset
;
108 dev
->readChunkWithTagsFromNAND(dev
,realignedChunk
,NULL
,&tags
);
109 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR
),
110 i
, tags
.objectId
,tags
.sequenceNumber
,tags
.eccResult
));
112 if(tags
.sequenceNumber
== YAFFS_SEQUENCE_CHECKPOINT_DATA
){
113 /* Right kind of block */
114 dev
->checkpointNextBlock
= tags
.objectId
;
115 dev
->checkpointCurrentBlock
= i
;
116 dev
->checkpointBlockList
[dev
->blocksInCheckpoint
] = i
;
117 dev
->blocksInCheckpoint
++;
118 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("found checkpt block %d"TENDSTR
),i
));
123 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("found no more checkpt blocks"TENDSTR
)));
125 dev
->checkpointNextBlock
= -1;
126 dev
->checkpointCurrentBlock
= -1;
130 int yaffs_CheckpointOpen(yaffs_Device
*dev
, int forWriting
)
133 /* Got the functions we need? */
134 if (!dev
->writeChunkWithTagsToNAND
||
135 !dev
->readChunkWithTagsFromNAND
||
136 !dev
->eraseBlockInNAND
||
137 !dev
->markNANDBlockBad
)
140 if(forWriting
&& !yaffs_CheckpointSpaceOk(dev
))
143 if(!dev
->checkpointBuffer
)
144 dev
->checkpointBuffer
= YMALLOC_DMA(dev
->nDataBytesPerChunk
);
145 if(!dev
->checkpointBuffer
)
149 dev
->checkpointPageSequence
= 0;
151 dev
->checkpointOpenForWrite
= forWriting
;
153 dev
->checkpointByteCount
= 0;
154 dev
->checkpointSum
= 0;
155 dev
->checkpointXor
= 0;
156 dev
->checkpointCurrentBlock
= -1;
157 dev
->checkpointCurrentChunk
= -1;
158 dev
->checkpointNextBlock
= dev
->internalStartBlock
;
160 /* Erase all the blocks in the checkpoint area */
162 memset(dev
->checkpointBuffer
,0,dev
->nDataBytesPerChunk
);
163 dev
->checkpointByteOffset
= 0;
164 return yaffs_CheckpointErase(dev
);
169 /* Set to a value that will kick off a read */
170 dev
->checkpointByteOffset
= dev
->nDataBytesPerChunk
;
171 /* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully)
172 * going to be way more than we need */
173 dev
->blocksInCheckpoint
= 0;
174 dev
->checkpointMaxBlocks
= (dev
->internalEndBlock
- dev
->internalStartBlock
)/16 + 2;
175 dev
->checkpointBlockList
= YMALLOC(sizeof(int) * dev
->checkpointMaxBlocks
);
176 for(i
= 0; i
< dev
->checkpointMaxBlocks
; i
++)
177 dev
->checkpointBlockList
[i
] = -1;
183 int yaffs_GetCheckpointSum(yaffs_Device
*dev
, __u32
*sum
)
186 compositeSum
= (dev
->checkpointSum
<< 8) | (dev
->checkpointXor
& 0xFF);
191 static int yaffs_CheckpointFlushBuffer(yaffs_Device
*dev
)
197 yaffs_ExtendedTags tags
;
199 if(dev
->checkpointCurrentBlock
< 0){
200 yaffs_CheckpointFindNextErasedBlock(dev
);
201 dev
->checkpointCurrentChunk
= 0;
204 if(dev
->checkpointCurrentBlock
< 0)
207 tags
.chunkDeleted
= 0;
208 tags
.objectId
= dev
->checkpointNextBlock
; /* Hint to next place to look */
209 tags
.chunkId
= dev
->checkpointPageSequence
+ 1;
210 tags
.sequenceNumber
= YAFFS_SEQUENCE_CHECKPOINT_DATA
;
211 tags
.byteCount
= dev
->nDataBytesPerChunk
;
212 if(dev
->checkpointCurrentChunk
== 0){
213 /* First chunk we write for the block? Set block state to
215 yaffs_BlockInfo
*bi
= yaffs_GetBlockInfo(dev
,dev
->checkpointCurrentBlock
);
216 bi
->blockState
= YAFFS_BLOCK_STATE_CHECKPOINT
;
217 dev
->blocksInCheckpoint
++;
220 chunk
= dev
->checkpointCurrentBlock
* dev
->nChunksPerBlock
+ dev
->checkpointCurrentChunk
;
223 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR
),
224 chunk
, dev
->checkpointCurrentBlock
, dev
->checkpointCurrentChunk
,tags
.objectId
,tags
.chunkId
));
226 realignedChunk
= chunk
- dev
->chunkOffset
;
228 dev
->writeChunkWithTagsToNAND(dev
,realignedChunk
,dev
->checkpointBuffer
,&tags
);
229 dev
->checkpointByteOffset
= 0;
230 dev
->checkpointPageSequence
++;
231 dev
->checkpointCurrentChunk
++;
232 if(dev
->checkpointCurrentChunk
>= dev
->nChunksPerBlock
){
233 dev
->checkpointCurrentChunk
= 0;
234 dev
->checkpointCurrentBlock
= -1;
236 memset(dev
->checkpointBuffer
,0,dev
->nDataBytesPerChunk
);
242 int yaffs_CheckpointWrite(yaffs_Device
*dev
,const void *data
, int nBytes
)
248 __u8
* dataBytes
= (__u8
*)data
;
252 if(!dev
->checkpointBuffer
)
255 if(!dev
->checkpointOpenForWrite
)
258 while(i
< nBytes
&& ok
) {
262 dev
->checkpointBuffer
[dev
->checkpointByteOffset
] = *dataBytes
;
263 dev
->checkpointSum
+= *dataBytes
;
264 dev
->checkpointXor
^= *dataBytes
;
266 dev
->checkpointByteOffset
++;
269 dev
->checkpointByteCount
++;
272 if(dev
->checkpointByteOffset
< 0 ||
273 dev
->checkpointByteOffset
>= dev
->nDataBytesPerChunk
)
274 ok
= yaffs_CheckpointFlushBuffer(dev
);
281 int yaffs_CheckpointRead(yaffs_Device
*dev
, void *data
, int nBytes
)
285 yaffs_ExtendedTags tags
;
291 __u8
*dataBytes
= (__u8
*)data
;
293 if(!dev
->checkpointBuffer
)
296 if(dev
->checkpointOpenForWrite
)
299 while(i
< nBytes
&& ok
) {
302 if(dev
->checkpointByteOffset
< 0 ||
303 dev
->checkpointByteOffset
>= dev
->nDataBytesPerChunk
) {
305 if(dev
->checkpointCurrentBlock
< 0){
306 yaffs_CheckpointFindNextCheckpointBlock(dev
);
307 dev
->checkpointCurrentChunk
= 0;
310 if(dev
->checkpointCurrentBlock
< 0)
314 chunk
= dev
->checkpointCurrentBlock
* dev
->nChunksPerBlock
+
315 dev
->checkpointCurrentChunk
;
317 realignedChunk
= chunk
- dev
->chunkOffset
;
319 /* read in the next chunk */
320 /* printf("read checkpoint page %d\n",dev->checkpointPage); */
321 dev
->readChunkWithTagsFromNAND(dev
, realignedChunk
,
322 dev
->checkpointBuffer
,
325 if(tags
.chunkId
!= (dev
->checkpointPageSequence
+ 1) ||
326 tags
.sequenceNumber
!= YAFFS_SEQUENCE_CHECKPOINT_DATA
)
329 dev
->checkpointByteOffset
= 0;
330 dev
->checkpointPageSequence
++;
331 dev
->checkpointCurrentChunk
++;
333 if(dev
->checkpointCurrentChunk
>= dev
->nChunksPerBlock
)
334 dev
->checkpointCurrentBlock
= -1;
339 *dataBytes
= dev
->checkpointBuffer
[dev
->checkpointByteOffset
];
340 dev
->checkpointSum
+= *dataBytes
;
341 dev
->checkpointXor
^= *dataBytes
;
342 dev
->checkpointByteOffset
++;
345 dev
->checkpointByteCount
++;
352 int yaffs_CheckpointClose(yaffs_Device
*dev
)
355 if(dev
->checkpointOpenForWrite
){
356 if(dev
->checkpointByteOffset
!= 0)
357 yaffs_CheckpointFlushBuffer(dev
);
360 for(i
= 0; i
< dev
->blocksInCheckpoint
&& dev
->checkpointBlockList
[i
] >= 0; i
++){
361 yaffs_BlockInfo
*bi
= yaffs_GetBlockInfo(dev
,dev
->checkpointBlockList
[i
]);
362 if(bi
->blockState
== YAFFS_BLOCK_STATE_EMPTY
)
363 bi
->blockState
= YAFFS_BLOCK_STATE_CHECKPOINT
;
365 // Todo this looks odd...
368 YFREE(dev
->checkpointBlockList
);
369 dev
->checkpointBlockList
= NULL
;
372 dev
->nFreeChunks
-= dev
->blocksInCheckpoint
* dev
->nChunksPerBlock
;
373 dev
->nErasedBlocks
-= dev
->blocksInCheckpoint
;
376 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("checkpoint byte count %d" TENDSTR
),
377 dev
->checkpointByteCount
));
379 if(dev
->checkpointBuffer
){
380 /* free the buffer */
381 YFREE(dev
->checkpointBuffer
);
382 dev
->checkpointBuffer
= NULL
;
390 int yaffs_CheckpointInvalidateStream(yaffs_Device
*dev
)
392 /* Erase the first checksum block */
394 T(YAFFS_TRACE_CHECKPOINT
,(TSTR("checkpoint invalidate"TENDSTR
)));
396 if(!yaffs_CheckpointSpaceOk(dev
))
399 return yaffs_CheckpointErase(dev
);