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.18 2009-03-06 17:20:49 wookey Exp $";
18 #include "yaffs_checkptrw.h"
19 #include "yaffs_getblockinfo.h"
21 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
),
29 return (blocksAvailable
<= 0) ? 0 : 1;
33 static int yaffs_CheckpointErase(yaffs_Device
*dev
)
37 if (!dev
->eraseBlockInNAND
)
39 T(YAFFS_TRACE_CHECKPOINT
, (TSTR("checking blocks %d to %d"TENDSTR
),
40 dev
->internalStartBlock
, dev
->internalEndBlock
));
42 for (i
= dev
->internalStartBlock
; i
<= dev
->internalEndBlock
; i
++) {
43 yaffs_BlockInfo
*bi
= yaffs_GetBlockInfo(dev
, i
);
44 if (bi
->blockState
== YAFFS_BLOCK_STATE_CHECKPOINT
) {
45 T(YAFFS_TRACE_CHECKPOINT
, (TSTR("erasing checkpt block %d"TENDSTR
), i
));
46 if (dev
->eraseBlockInNAND(dev
, i
- dev
->blockOffset
/* realign */)) {
47 bi
->blockState
= YAFFS_BLOCK_STATE_EMPTY
;
49 dev
->nFreeChunks
+= dev
->nChunksPerBlock
;
51 dev
->markNANDBlockBad(dev
, i
);
52 bi
->blockState
= YAFFS_BLOCK_STATE_DEAD
;
57 dev
->blocksInCheckpoint
= 0;
63 static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device
*dev
)
66 int blocksAvailable
= dev
->nErasedBlocks
- dev
->nReservedBlocks
;
67 T(YAFFS_TRACE_CHECKPOINT
,
68 (TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR
),
69 dev
->nErasedBlocks
, dev
->nReservedBlocks
, blocksAvailable
, dev
->checkpointNextBlock
));
71 if (dev
->checkpointNextBlock
>= 0 &&
72 dev
->checkpointNextBlock
<= dev
->internalEndBlock
&&
73 blocksAvailable
> 0) {
75 for (i
= dev
->checkpointNextBlock
; i
<= dev
->internalEndBlock
; i
++) {
76 yaffs_BlockInfo
*bi
= yaffs_GetBlockInfo(dev
, i
);
77 if (bi
->blockState
== YAFFS_BLOCK_STATE_EMPTY
) {
78 dev
->checkpointNextBlock
= i
+ 1;
79 dev
->checkpointCurrentBlock
= i
;
80 T(YAFFS_TRACE_CHECKPOINT
, (TSTR("allocating checkpt block %d"TENDSTR
), i
));
85 T(YAFFS_TRACE_CHECKPOINT
, (TSTR("out of checkpt blocks"TENDSTR
)));
87 dev
->checkpointNextBlock
= -1;
88 dev
->checkpointCurrentBlock
= -1;
91 static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device
*dev
)
94 yaffs_ExtendedTags tags
;
96 T(YAFFS_TRACE_CHECKPOINT
, (TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR
),
97 dev
->blocksInCheckpoint
, dev
->checkpointNextBlock
));
99 if (dev
->blocksInCheckpoint
< dev
->checkpointMaxBlocks
)
100 for (i
= dev
->checkpointNextBlock
; i
<= dev
->internalEndBlock
; i
++) {
101 int chunk
= i
* dev
->nChunksPerBlock
;
102 int realignedChunk
= chunk
- dev
->chunkOffset
;
104 dev
->readChunkWithTagsFromNAND(dev
, realignedChunk
,
106 T(YAFFS_TRACE_CHECKPOINT
, (TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR
),
107 i
, tags
.objectId
, tags
.sequenceNumber
, tags
.eccResult
));
109 if (tags
.sequenceNumber
== YAFFS_SEQUENCE_CHECKPOINT_DATA
) {
110 /* Right kind of block */
111 dev
->checkpointNextBlock
= tags
.objectId
;
112 dev
->checkpointCurrentBlock
= i
;
113 dev
->checkpointBlockList
[dev
->blocksInCheckpoint
] = i
;
114 dev
->blocksInCheckpoint
++;
115 T(YAFFS_TRACE_CHECKPOINT
, (TSTR("found checkpt block %d"TENDSTR
), i
));
120 T(YAFFS_TRACE_CHECKPOINT
, (TSTR("found no more checkpt blocks"TENDSTR
)));
122 dev
->checkpointNextBlock
= -1;
123 dev
->checkpointCurrentBlock
= -1;
127 int yaffs_CheckpointOpen(yaffs_Device
*dev
, int forWriting
)
130 /* Got the functions we need? */
131 if (!dev
->writeChunkWithTagsToNAND
||
132 !dev
->readChunkWithTagsFromNAND
||
133 !dev
->eraseBlockInNAND
||
134 !dev
->markNANDBlockBad
)
137 if (forWriting
&& !yaffs_CheckpointSpaceOk(dev
))
140 if (!dev
->checkpointBuffer
)
141 dev
->checkpointBuffer
= YMALLOC_DMA(dev
->totalBytesPerChunk
);
142 if (!dev
->checkpointBuffer
)
146 dev
->checkpointPageSequence
= 0;
148 dev
->checkpointOpenForWrite
= forWriting
;
150 dev
->checkpointByteCount
= 0;
151 dev
->checkpointSum
= 0;
152 dev
->checkpointXor
= 0;
153 dev
->checkpointCurrentBlock
= -1;
154 dev
->checkpointCurrentChunk
= -1;
155 dev
->checkpointNextBlock
= dev
->internalStartBlock
;
157 /* Erase all the blocks in the checkpoint area */
159 memset(dev
->checkpointBuffer
, 0, dev
->nDataBytesPerChunk
);
160 dev
->checkpointByteOffset
= 0;
161 return yaffs_CheckpointErase(dev
);
164 /* Set to a value that will kick off a read */
165 dev
->checkpointByteOffset
= dev
->nDataBytesPerChunk
;
166 /* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully)
167 * going to be way more than we need */
168 dev
->blocksInCheckpoint
= 0;
169 dev
->checkpointMaxBlocks
= (dev
->internalEndBlock
- dev
->internalStartBlock
)/16 + 2;
170 dev
->checkpointBlockList
= YMALLOC(sizeof(int) * dev
->checkpointMaxBlocks
);
171 for (i
= 0; i
< dev
->checkpointMaxBlocks
; i
++)
172 dev
->checkpointBlockList
[i
] = -1;
178 int yaffs_GetCheckpointSum(yaffs_Device
*dev
, __u32
*sum
)
181 compositeSum
= (dev
->checkpointSum
<< 8) | (dev
->checkpointXor
& 0xFF);
186 static int yaffs_CheckpointFlushBuffer(yaffs_Device
*dev
)
191 yaffs_ExtendedTags tags
;
193 if (dev
->checkpointCurrentBlock
< 0) {
194 yaffs_CheckpointFindNextErasedBlock(dev
);
195 dev
->checkpointCurrentChunk
= 0;
198 if (dev
->checkpointCurrentBlock
< 0)
201 tags
.chunkDeleted
= 0;
202 tags
.objectId
= dev
->checkpointNextBlock
; /* Hint to next place to look */
203 tags
.chunkId
= dev
->checkpointPageSequence
+ 1;
204 tags
.sequenceNumber
= YAFFS_SEQUENCE_CHECKPOINT_DATA
;
205 tags
.byteCount
= dev
->nDataBytesPerChunk
;
206 if (dev
->checkpointCurrentChunk
== 0) {
207 /* First chunk we write for the block? Set block state to
209 yaffs_BlockInfo
*bi
= yaffs_GetBlockInfo(dev
, dev
->checkpointCurrentBlock
);
210 bi
->blockState
= YAFFS_BLOCK_STATE_CHECKPOINT
;
211 dev
->blocksInCheckpoint
++;
214 chunk
= dev
->checkpointCurrentBlock
* dev
->nChunksPerBlock
+ dev
->checkpointCurrentChunk
;
217 T(YAFFS_TRACE_CHECKPOINT
, (TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR
),
218 chunk
, dev
->checkpointCurrentBlock
, dev
->checkpointCurrentChunk
, tags
.objectId
, tags
.chunkId
));
220 realignedChunk
= chunk
- dev
->chunkOffset
;
222 dev
->writeChunkWithTagsToNAND(dev
, realignedChunk
,
223 dev
->checkpointBuffer
, &tags
);
224 dev
->checkpointByteOffset
= 0;
225 dev
->checkpointPageSequence
++;
226 dev
->checkpointCurrentChunk
++;
227 if (dev
->checkpointCurrentChunk
>= dev
->nChunksPerBlock
) {
228 dev
->checkpointCurrentChunk
= 0;
229 dev
->checkpointCurrentBlock
= -1;
231 memset(dev
->checkpointBuffer
, 0, dev
->nDataBytesPerChunk
);
237 int yaffs_CheckpointWrite(yaffs_Device
*dev
, const void *data
, int nBytes
)
243 __u8
* dataBytes
= (__u8
*)data
;
247 if (!dev
->checkpointBuffer
)
250 if (!dev
->checkpointOpenForWrite
)
253 while (i
< nBytes
&& ok
) {
254 dev
->checkpointBuffer
[dev
->checkpointByteOffset
] = *dataBytes
;
255 dev
->checkpointSum
+= *dataBytes
;
256 dev
->checkpointXor
^= *dataBytes
;
258 dev
->checkpointByteOffset
++;
261 dev
->checkpointByteCount
++;
264 if (dev
->checkpointByteOffset
< 0 ||
265 dev
->checkpointByteOffset
>= dev
->nDataBytesPerChunk
)
266 ok
= yaffs_CheckpointFlushBuffer(dev
);
272 int yaffs_CheckpointRead(yaffs_Device
*dev
, void *data
, int nBytes
)
276 yaffs_ExtendedTags tags
;
282 __u8
*dataBytes
= (__u8
*)data
;
284 if (!dev
->checkpointBuffer
)
287 if (dev
->checkpointOpenForWrite
)
290 while (i
< nBytes
&& ok
) {
293 if (dev
->checkpointByteOffset
< 0 ||
294 dev
->checkpointByteOffset
>= dev
->nDataBytesPerChunk
) {
296 if (dev
->checkpointCurrentBlock
< 0) {
297 yaffs_CheckpointFindNextCheckpointBlock(dev
);
298 dev
->checkpointCurrentChunk
= 0;
301 if (dev
->checkpointCurrentBlock
< 0)
304 chunk
= dev
->checkpointCurrentBlock
*
305 dev
->nChunksPerBlock
+
306 dev
->checkpointCurrentChunk
;
308 realignedChunk
= chunk
- dev
->chunkOffset
;
310 /* read in the next chunk */
311 /* printf("read checkpoint page %d\n",dev->checkpointPage); */
312 dev
->readChunkWithTagsFromNAND(dev
,
314 dev
->checkpointBuffer
,
317 if (tags
.chunkId
!= (dev
->checkpointPageSequence
+ 1) ||
318 tags
.eccResult
> YAFFS_ECC_RESULT_FIXED
||
319 tags
.sequenceNumber
!= YAFFS_SEQUENCE_CHECKPOINT_DATA
)
322 dev
->checkpointByteOffset
= 0;
323 dev
->checkpointPageSequence
++;
324 dev
->checkpointCurrentChunk
++;
326 if (dev
->checkpointCurrentChunk
>= dev
->nChunksPerBlock
)
327 dev
->checkpointCurrentBlock
= -1;
332 *dataBytes
= dev
->checkpointBuffer
[dev
->checkpointByteOffset
];
333 dev
->checkpointSum
+= *dataBytes
;
334 dev
->checkpointXor
^= *dataBytes
;
335 dev
->checkpointByteOffset
++;
338 dev
->checkpointByteCount
++;
345 int yaffs_CheckpointClose(yaffs_Device
*dev
)
348 if (dev
->checkpointOpenForWrite
) {
349 if (dev
->checkpointByteOffset
!= 0)
350 yaffs_CheckpointFlushBuffer(dev
);
353 for (i
= 0; i
< dev
->blocksInCheckpoint
&& dev
->checkpointBlockList
[i
] >= 0; i
++) {
354 yaffs_BlockInfo
*bi
= yaffs_GetBlockInfo(dev
, dev
->checkpointBlockList
[i
]);
355 if (bi
->blockState
== YAFFS_BLOCK_STATE_EMPTY
)
356 bi
->blockState
= YAFFS_BLOCK_STATE_CHECKPOINT
;
358 /* Todo this looks odd... */
361 YFREE(dev
->checkpointBlockList
);
362 dev
->checkpointBlockList
= NULL
;
365 dev
->nFreeChunks
-= dev
->blocksInCheckpoint
* dev
->nChunksPerBlock
;
366 dev
->nErasedBlocks
-= dev
->blocksInCheckpoint
;
369 T(YAFFS_TRACE_CHECKPOINT
, (TSTR("checkpoint byte count %d" TENDSTR
),
370 dev
->checkpointByteCount
));
372 if (dev
->checkpointBuffer
) {
373 /* free the buffer */
374 YFREE(dev
->checkpointBuffer
);
375 dev
->checkpointBuffer
= NULL
;
381 int yaffs_CheckpointInvalidateStream(yaffs_Device
*dev
)
383 /* Erase the first checksum block */
385 T(YAFFS_TRACE_CHECKPOINT
, (TSTR("checkpoint invalidate"TENDSTR
)));
387 if (!yaffs_CheckpointSpaceOk(dev
))
390 return yaffs_CheckpointErase(dev
);