Checkpointing changes
[yaffs2.git] / yaffs_checkptrw.c
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.1 2006-05-08 10:13:34 charles Exp $";
17
18
19 #include "yaffs_checkptrw.h"
20
21
22 int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
23 {
24
25         T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpt blocks %d %d %d %d" TENDSTR),
26                 dev->checkpointStartBlock, dev->checkpointEndBlock,
27                 dev->startBlock,dev->endBlock));
28                 
29         if(dev->checkpointStartBlock >= dev->checkpointEndBlock)
30                 return 0;
31                 
32         if(dev->checkpointStartBlock >= dev->startBlock && 
33            dev->checkpointStartBlock <= dev->endBlock)
34                 return 0;
35
36         if(dev->checkpointEndBlock >= dev->startBlock && 
37            dev->checkpointEndBlock <= dev->endBlock)
38                 return 0;
39                 
40         return 1;
41 }
42
43 int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
44 {
45         int i;
46         
47         /* Got the functions we need? */
48         if (!dev->writeChunkWithTagsToNAND ||
49             !dev->readChunkWithTagsFromNAND ||
50             !dev->eraseBlockInNAND)
51                 return 0;
52         
53         /* Got a valid checkpoint data region? */
54         if(!yaffs_CheckpointSpaceOk(dev))
55                 return 0;
56                         
57         if(!dev->checkpointBuffer)
58                 dev->checkpointBuffer = YMALLOC(dev->nBytesPerChunk);
59         if(!dev->checkpointBuffer)
60                 return 0;
61         
62         dev->checkpointPage = dev->checkpointStartBlock * dev->nChunksPerBlock;
63         
64         dev->checkpointOpenForWrite = forWriting;
65         
66         dev->checkpointByteCount = 0;
67         
68         /* Erase all the blocks in the checkpoint area */
69         if(forWriting){
70                 T(YAFFS_TRACE_CHECKPOINT,(TSTR("erasing checkpt data"TENDSTR)));
71                 for( i = dev->checkpointStartBlock; i <= dev->checkpointEndBlock; i++)
72                         dev->eraseBlockInNAND(dev,i);
73                 
74                 dev->checkpointByteOffset = 0;
75                 
76                 memset(dev->checkpointBuffer,0,dev->nBytesPerChunk);
77                 
78         } else {
79                 /* Set to a value that will kick off a read */
80                 dev->checkpointByteOffset = dev->nBytesPerChunk;
81         }
82         
83         return 1;
84 }
85
86 static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)
87 {
88
89         int blockNo;
90         int goodBlockFound;
91         yaffs_BlockState state;
92         __u32 seqenceNumber;
93
94         yaffs_ExtendedTags tags;
95         tags.chunkDeleted = 0;
96         tags.objectId = YAFFS_OBJECTID_CHECKPOINT_DATA;
97         tags.chunkId = dev->checkpointPage + 1;
98         tags.sequenceNumber = 1;
99         tags.byteCount = dev->nBytesPerChunk;
100         
101         /* printf("write checkpoint page %d\n",dev->checkpointPage); */
102         
103         if(dev->checkpointPage%dev->nChunksPerBlock == 0){
104                 /* Start of a new block, do a block validity check */
105                 blockNo = dev->checkpointPage/dev->nChunksPerBlock;
106                 goodBlockFound = 0;
107                 while(blockNo <= dev->checkpointEndBlock && !goodBlockFound){
108                         dev->queryNANDBlock(dev,blockNo,&state,&tags);
109                         if(state != YAFFS_BLOCK_STATE_DEAD)
110                                 goodBlockFound = 1;
111                         else {
112                                 blockNo++;
113                                 dev->checkpointPage += dev->nChunksPerBlock;
114                         }
115                 }
116                 
117                 if(!goodBlockFound)
118                         return 0;
119         }
120         
121         dev->writeChunkWithTagsToNAND(dev, dev->checkpointPage, 
122                                       dev->checkpointBuffer,&tags);
123         dev->checkpointByteOffset = 0;
124         dev->checkpointPage++;     
125         memset(dev->checkpointBuffer,0,dev->nBytesPerChunk);
126         
127         return 1;
128 }
129
130 int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes)
131 {
132         int i=0;
133         int ok = 1;
134
135         
136         __u8 * dataBytes = (__u8 *)data;
137         
138         
139
140         if(!dev->checkpointBuffer)
141                 return 0;
142
143         while(i < nBytes && ok) {
144                 
145
146                 
147                  dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes ;
148                 dev->checkpointByteOffset++;
149                 i++;
150                 dataBytes++;
151                 dev->checkpointByteCount++;
152                 
153                 
154                 if(dev->checkpointByteOffset < 0 ||
155                    dev->checkpointByteOffset >= dev->nBytesPerChunk) 
156                         ok = yaffs_CheckpointFlushBuffer(dev);
157
158         }
159         
160         return  i;
161 }
162
163 int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
164 {
165         int i=0;
166         int ok = 1;
167         yaffs_ExtendedTags tags;
168         yaffs_BlockState state;
169         int blockNo;
170         int goodBlockFound;
171
172         __u8 *dataBytes = (__u8 *)data;
173                 
174         if(!dev->checkpointBuffer)
175                 return 0;
176
177         while(i < nBytes && ok) {
178                 if(dev->checkpointByteOffset < 0 ||
179                    dev->checkpointByteOffset >= dev->nBytesPerChunk) {
180                         if(dev->checkpointPage%dev->nChunksPerBlock == 0){
181                                 /* Start of a new block, do a block validity check */
182                                 blockNo = dev->checkpointPage/dev->nChunksPerBlock;
183                                 goodBlockFound = 0;
184                                 while(blockNo <= dev->checkpointEndBlock && !goodBlockFound){
185                                         dev->queryNANDBlock(dev,blockNo,&state,&tags);
186                                         if(state != YAFFS_BLOCK_STATE_DEAD)
187                                                 goodBlockFound = 1;
188                                         else {
189                                                 blockNo++;
190                                                 dev->checkpointPage += dev->nChunksPerBlock;
191                                         }
192                                 }
193                 
194                                 if(!goodBlockFound)
195                                         return 0;
196                         }
197
198
199                         /* read in the next chunk */
200                         /* printf("read checkpoint page %d\n",dev->checkpointPage); */
201                         dev->readChunkWithTagsFromNAND(dev, dev->checkpointPage, 
202                                                        dev->checkpointBuffer,
203                                                       &tags);
204                                                       
205                         if(tags.objectId != YAFFS_OBJECTID_CHECKPOINT_DATA ||
206                            tags.chunkId != (dev->checkpointPage + 1))
207                            ok = 0;
208
209                         dev->checkpointByteOffset = 0;
210                         dev->checkpointPage++;
211                 }
212                 
213                 if(ok){
214                         *dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset];
215                         dev->checkpointByteOffset++;
216                         i++;
217                         dataBytes++;
218                         dev->checkpointByteCount++;
219                 }
220         }
221         
222         return  i;
223 }
224
225 int yaffs_CheckpointClose(yaffs_Device *dev)
226 {
227
228         if(dev->checkpointOpenForWrite){        
229                 if(dev->checkpointByteOffset != 0)
230                         yaffs_CheckpointFlushBuffer(dev);
231         }
232
233         T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint byte count %d" TENDSTR),
234                         dev->checkpointByteCount));
235                         
236         if(dev->checkpointBuffer){
237                 /* flush the buffer */  
238                 YFREE(dev->checkpointBuffer);
239                 dev->checkpointBuffer = NULL;
240                 return 1;
241         }
242         else
243                 return 0;
244         
245 }
246
247 int yaffs_CheckpointInvalidateStream(yaffs_Device *dev)
248 {
249         /* Erase the first checksum block */
250
251         T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint invalidate"TENDSTR)));
252
253         if(!yaffs_CheckpointSpaceOk(dev))
254                 return 0;
255
256         if(dev->eraseBlockInNAND){
257                 T(YAFFS_TRACE_CHECKPOINT,(TSTR("erasing checkpt data"TENDSTR)));
258
259                 return dev->eraseBlockInNAND(dev, dev->checkpointStartBlock);
260         }
261         else
262                 return 0;
263 }
264
265
266