• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * YAFFS: Yet another FFS. A NAND-flash specific file system.
3  *
4  * Copyright (C) 2002 Aleph One Ltd.
5  *   for Toby Churchill Ltd and Brightstar Engineering
6  *
7  * Created by Charles Manning <charles@aleph1.co.uk>
8  *
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.
12  *
13  */
14 
15 const char *yaffs_checkptrw_c_version =
16     "$Id: yaffs_checkptrw.c,v 1.5 2006/10/03 10:13:03 charles Exp $";
17 
18 
19 #include "yaffs_checkptrw.h"
20 
21 
yaffs_CheckpointSpaceOk(yaffs_Device * dev)22 static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
23 {
24 
25 	int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
26 
27 	T(YAFFS_TRACE_CHECKPOINT,
28 		(TSTR("checkpt blocks available = %d" TENDSTR),
29 		blocksAvailable));
30 
31 
32 	return (blocksAvailable <= 0) ? 0 : 1;
33 }
34 
35 
36 
yaffs_CheckpointErase(yaffs_Device * dev)37 static int yaffs_CheckpointErase(yaffs_Device *dev)
38 {
39 
40 	int i;
41 
42 
43 	if(!dev->eraseBlockInNAND)
44 		return 0;
45 	T(YAFFS_TRACE_CHECKPOINT,(TSTR("checking blocks %d to %d"TENDSTR),
46 		dev->startBlock,dev->endBlock));
47 
48 	for(i = dev->startBlock; i <= dev->endBlock; i++) {
49 		yaffs_BlockInfo *bi = &dev->blockInfo[i];
50 		if(bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT){
51 			T(YAFFS_TRACE_CHECKPOINT,(TSTR("erasing checkpt block %d"TENDSTR),i));
52 			if(dev->eraseBlockInNAND(dev,i)){
53 				bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
54 				dev->nErasedBlocks++;
55 				dev->nFreeChunks += dev->nChunksPerBlock;
56 			}
57 			else {
58 				dev->markNANDBlockBad(dev,i);
59 				bi->blockState = YAFFS_BLOCK_STATE_DEAD;
60 			}
61 		}
62 	}
63 
64 	dev->blocksInCheckpoint = 0;
65 
66 	return 1;
67 }
68 
69 
yaffs_CheckpointFindNextErasedBlock(yaffs_Device * dev)70 static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev)
71 {
72 	int  i;
73 	int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
74 
75 	if(dev->checkpointNextBlock >= 0 &&
76 	   dev->checkpointNextBlock <= dev->endBlock &&
77 	   blocksAvailable > 0){
78 
79 		for(i = dev->checkpointNextBlock; i <= dev->endBlock; i++){
80 			yaffs_BlockInfo *bi = &dev->blockInfo[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));
85 				return;
86 			}
87 		}
88 	}
89 	T(YAFFS_TRACE_CHECKPOINT,(TSTR("out of checkpt blocks"TENDSTR)));
90 
91 	dev->checkpointNextBlock = -1;
92 	dev->checkpointCurrentBlock = -1;
93 }
94 
yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device * dev)95 static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
96 {
97 	int  i;
98 	yaffs_ExtendedTags tags;
99 
100 	if(dev->blocksInCheckpoint < dev->checkpointMaxBlocks)
101 		for(i = dev->checkpointNextBlock; i <= dev->endBlock; i++){
102 			int chunk = i * dev->nChunksPerBlock;
103 
104 			dev->readChunkWithTagsFromNAND(dev,chunk,NULL,&tags);
105 
106 			if(tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA){
107 				/* Right kind of block */
108 				dev->checkpointNextBlock = tags.objectId;
109 				dev->checkpointCurrentBlock = i;
110 				dev->checkpointBlockList[dev->blocksInCheckpoint] = i;
111 				dev->blocksInCheckpoint++;
112 				T(YAFFS_TRACE_CHECKPOINT,(TSTR("found checkpt block %d"TENDSTR),i));
113 				return;
114 			}
115 		}
116 
117 	T(YAFFS_TRACE_CHECKPOINT,(TSTR("found no more checkpt blocks"TENDSTR)));
118 
119 	dev->checkpointNextBlock = -1;
120 	dev->checkpointCurrentBlock = -1;
121 }
122 
123 
yaffs_CheckpointOpen(yaffs_Device * dev,int forWriting)124 int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
125 {
126 
127 	/* Got the functions we need? */
128 	if (!dev->writeChunkWithTagsToNAND ||
129 	    !dev->readChunkWithTagsFromNAND ||
130 	    !dev->eraseBlockInNAND ||
131 	    !dev->markNANDBlockBad)
132 		return 0;
133 
134 	if(forWriting && !yaffs_CheckpointSpaceOk(dev))
135 		return 0;
136 
137 	if(!dev->checkpointBuffer)
138 		dev->checkpointBuffer = YMALLOC_DMA(dev->nDataBytesPerChunk);
139 	if(!dev->checkpointBuffer)
140 		return 0;
141 
142 
143 	dev->checkpointPageSequence = 0;
144 
145 	dev->checkpointOpenForWrite = forWriting;
146 
147 	dev->checkpointByteCount = 0;
148 	dev->checkpointCurrentBlock = -1;
149 	dev->checkpointCurrentChunk = -1;
150 	dev->checkpointNextBlock = dev->startBlock;
151 
152 	/* Erase all the blocks in the checkpoint area */
153 	if(forWriting){
154 		memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk);
155 		dev->checkpointByteOffset = 0;
156 		return yaffs_CheckpointErase(dev);
157 
158 
159 	} else {
160 		int i;
161 		/* Set to a value that will kick off a read */
162 		dev->checkpointByteOffset = dev->nDataBytesPerChunk;
163 		/* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully)
164 		 * going to be way more than we need */
165 		dev->blocksInCheckpoint = 0;
166 		dev->checkpointMaxBlocks = (dev->endBlock - dev->startBlock)/16 + 2;
167 		dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks);
168 		for(i = 0; i < dev->checkpointMaxBlocks; i++)
169 			dev->checkpointBlockList[i] = -1;
170 	}
171 
172 	return 1;
173 }
174 
yaffs_CheckpointFlushBuffer(yaffs_Device * dev)175 static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)
176 {
177 
178 	int chunk;
179 
180 	yaffs_ExtendedTags tags;
181 
182 	if(dev->checkpointCurrentBlock < 0){
183 		yaffs_CheckpointFindNextErasedBlock(dev);
184 		dev->checkpointCurrentChunk = 0;
185 	}
186 
187 	if(dev->checkpointCurrentBlock < 0)
188 		return 0;
189 
190 	tags.chunkDeleted = 0;
191 	tags.objectId = dev->checkpointNextBlock; /* Hint to next place to look */
192 	tags.chunkId = dev->checkpointPageSequence + 1;
193 	tags.sequenceNumber =  YAFFS_SEQUENCE_CHECKPOINT_DATA;
194 	tags.byteCount = dev->nDataBytesPerChunk;
195 	if(dev->checkpointCurrentChunk == 0){
196 		/* First chunk we write for the block? Set block state to
197 		   checkpoint */
198 		yaffs_BlockInfo *bi = &dev->blockInfo[dev->checkpointCurrentBlock];
199 		bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
200 		dev->blocksInCheckpoint++;
201 	}
202 
203 	chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk;
204 
205 	dev->writeChunkWithTagsToNAND(dev,chunk,dev->checkpointBuffer,&tags);
206 	dev->checkpointByteOffset = 0;
207 	dev->checkpointPageSequence++;
208 	dev->checkpointCurrentChunk++;
209 	if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock){
210 		dev->checkpointCurrentChunk = 0;
211 		dev->checkpointCurrentBlock = -1;
212 	}
213 	memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk);
214 
215 	return 1;
216 }
217 
218 
yaffs_CheckpointWrite(yaffs_Device * dev,const void * data,int nBytes)219 int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes)
220 {
221 	int i=0;
222 	int ok = 1;
223 
224 
225 	__u8 * dataBytes = (__u8 *)data;
226 
227 
228 
229 	if(!dev->checkpointBuffer)
230 		return 0;
231 
232 	while(i < nBytes && ok) {
233 
234 
235 
236 		 dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes ;
237 		dev->checkpointByteOffset++;
238 		i++;
239 		dataBytes++;
240 		dev->checkpointByteCount++;
241 
242 
243 		if(dev->checkpointByteOffset < 0 ||
244 		   dev->checkpointByteOffset >= dev->nDataBytesPerChunk)
245 			ok = yaffs_CheckpointFlushBuffer(dev);
246 
247 	}
248 
249 	return 	i;
250 }
251 
yaffs_CheckpointRead(yaffs_Device * dev,void * data,int nBytes)252 int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
253 {
254 	int i=0;
255 	int ok = 1;
256 	yaffs_ExtendedTags tags;
257 
258 
259 	int chunk;
260 
261 	__u8 *dataBytes = (__u8 *)data;
262 
263 	if(!dev->checkpointBuffer)
264 		return 0;
265 
266 	while(i < nBytes && ok) {
267 
268 
269 		if(dev->checkpointByteOffset < 0 ||
270 		   dev->checkpointByteOffset >= dev->nDataBytesPerChunk) {
271 
272 		   	if(dev->checkpointCurrentBlock < 0){
273 				yaffs_CheckpointFindNextCheckpointBlock(dev);
274 				dev->checkpointCurrentChunk = 0;
275 			}
276 
277 			if(dev->checkpointCurrentBlock < 0)
278 				ok = 0;
279 			else {
280 
281 				chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock +
282 				          dev->checkpointCurrentChunk;
283 
284 	   			/* read in the next chunk */
285 	   			/* printf("read checkpoint page %d\n",dev->checkpointPage); */
286 				dev->readChunkWithTagsFromNAND(dev, chunk,
287 							       dev->checkpointBuffer,
288 							      &tags);
289 
290 				if(tags.chunkId != (dev->checkpointPageSequence + 1) ||
291 				   tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA)
292 				   ok = 0;
293 
294 				dev->checkpointByteOffset = 0;
295 				dev->checkpointPageSequence++;
296 				dev->checkpointCurrentChunk++;
297 
298 				if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock)
299 					dev->checkpointCurrentBlock = -1;
300 			}
301 		}
302 
303 		if(ok){
304 			*dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset];
305 			dev->checkpointByteOffset++;
306 			i++;
307 			dataBytes++;
308 			dev->checkpointByteCount++;
309 		}
310 	}
311 
312 	return 	i;
313 }
314 
yaffs_CheckpointClose(yaffs_Device * dev)315 int yaffs_CheckpointClose(yaffs_Device *dev)
316 {
317 
318 	if(dev->checkpointOpenForWrite){
319 		if(dev->checkpointByteOffset != 0)
320 			yaffs_CheckpointFlushBuffer(dev);
321 	} else {
322 		int i;
323 		for(i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++){
324 			yaffs_BlockInfo *bi = &dev->blockInfo[dev->checkpointBlockList[i]];
325 			if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
326 				bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
327 			else {
328 				// Todo this looks odd...
329 			}
330 		}
331 		YFREE(dev->checkpointBlockList);
332 		dev->checkpointBlockList = NULL;
333 	}
334 
335 	dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock;
336 	dev->nErasedBlocks -= dev->blocksInCheckpoint;
337 
338 
339 	T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint byte count %d" TENDSTR),
340 			dev->checkpointByteCount));
341 
342 	if(dev->checkpointBuffer){
343 		/* free the buffer */
344 		YFREE(dev->checkpointBuffer);
345 		dev->checkpointBuffer = NULL;
346 		return 1;
347 	}
348 	else
349 		return 0;
350 
351 }
352 
yaffs_CheckpointInvalidateStream(yaffs_Device * dev)353 int yaffs_CheckpointInvalidateStream(yaffs_Device *dev)
354 {
355 	/* Erase the first checksum block */
356 
357 	T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint invalidate"TENDSTR)));
358 
359 	if(!yaffs_CheckpointSpaceOk(dev))
360 		return 0;
361 
362 	return yaffs_CheckpointErase(dev);
363 }
364 
365 
366 
367