Root/target/linux/generic/files/fs/yaffs2/yaffs_checkptrw.c

1/*
2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2007 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
14const char *yaffs_checkptrw_c_version =
15    "$Id: yaffs_checkptrw.c,v 1.14 2007-05-15 20:07:40 charles Exp $";
16
17
18#include "yaffs_checkptrw.h"
19
20
21static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
22{
23
24    int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
25
26    T(YAFFS_TRACE_CHECKPOINT,
27        (TSTR("checkpt blocks available = %d" TENDSTR),
28        blocksAvailable));
29
30
31    return (blocksAvailable <= 0) ? 0 : 1;
32}
33
34
35static int yaffs_CheckpointErase(yaffs_Device *dev)
36{
37
38    int i;
39
40
41    if(!dev->eraseBlockInNAND)
42        return 0;
43    T(YAFFS_TRACE_CHECKPOINT,(TSTR("checking blocks %d to %d"TENDSTR),
44        dev->internalStartBlock,dev->internalEndBlock));
45
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;
52                dev->nErasedBlocks++;
53                dev->nFreeChunks += dev->nChunksPerBlock;
54            }
55            else {
56                dev->markNANDBlockBad(dev,i);
57                bi->blockState = YAFFS_BLOCK_STATE_DEAD;
58            }
59        }
60    }
61
62    dev->blocksInCheckpoint = 0;
63
64    return 1;
65}
66
67
68static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev)
69{
70    int i;
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));
75
76    if(dev->checkpointNextBlock >= 0 &&
77       dev->checkpointNextBlock <= dev->internalEndBlock &&
78       blocksAvailable > 0){
79
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));
86                return;
87            }
88        }
89    }
90    T(YAFFS_TRACE_CHECKPOINT,(TSTR("out of checkpt blocks"TENDSTR)));
91
92    dev->checkpointNextBlock = -1;
93    dev->checkpointCurrentBlock = -1;
94}
95
96static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
97{
98    int i;
99    yaffs_ExtendedTags tags;
100
101    T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR),
102        dev->blocksInCheckpoint, dev->checkpointNextBlock));
103
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;
108
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));
112
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));
120                return;
121            }
122        }
123
124    T(YAFFS_TRACE_CHECKPOINT,(TSTR("found no more checkpt blocks"TENDSTR)));
125
126    dev->checkpointNextBlock = -1;
127    dev->checkpointCurrentBlock = -1;
128}
129
130
131int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
132{
133
134    /* Got the functions we need? */
135    if (!dev->writeChunkWithTagsToNAND ||
136        !dev->readChunkWithTagsFromNAND ||
137        !dev->eraseBlockInNAND ||
138        !dev->markNANDBlockBad)
139        return 0;
140
141    if(forWriting && !yaffs_CheckpointSpaceOk(dev))
142        return 0;
143
144    if(!dev->checkpointBuffer)
145        dev->checkpointBuffer = YMALLOC_DMA(dev->nDataBytesPerChunk);
146    if(!dev->checkpointBuffer)
147        return 0;
148
149
150    dev->checkpointPageSequence = 0;
151
152    dev->checkpointOpenForWrite = forWriting;
153
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;
160
161    /* Erase all the blocks in the checkpoint area */
162    if(forWriting){
163        memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk);
164        dev->checkpointByteOffset = 0;
165        return yaffs_CheckpointErase(dev);
166
167
168    } else {
169        int i;
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;
179    }
180
181    return 1;
182}
183
184int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum)
185{
186    __u32 compositeSum;
187    compositeSum = (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF);
188    *sum = compositeSum;
189    return 1;
190}
191
192static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)
193{
194
195    int chunk;
196    int realignedChunk;
197
198    yaffs_ExtendedTags tags;
199
200    if(dev->checkpointCurrentBlock < 0){
201        yaffs_CheckpointFindNextErasedBlock(dev);
202        dev->checkpointCurrentChunk = 0;
203    }
204
205    if(dev->checkpointCurrentBlock < 0)
206        return 0;
207
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
215           checkpoint */
216        yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,dev->checkpointCurrentBlock);
217        bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
218        dev->blocksInCheckpoint++;
219    }
220
221    chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk;
222
223
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));
226
227    realignedChunk = chunk - dev->chunkOffset;
228
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;
236    }
237    memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk);
238
239    return 1;
240}
241
242
243int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes)
244{
245    int i=0;
246    int ok = 1;
247
248
249    __u8 * dataBytes = (__u8 *)data;
250
251
252
253    if(!dev->checkpointBuffer)
254        return 0;
255
256    if(!dev->checkpointOpenForWrite)
257        return -1;
258
259    while(i < nBytes && ok) {
260
261
262
263        dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes ;
264        dev->checkpointSum += *dataBytes;
265        dev->checkpointXor ^= *dataBytes;
266
267        dev->checkpointByteOffset++;
268        i++;
269        dataBytes++;
270        dev->checkpointByteCount++;
271
272
273        if(dev->checkpointByteOffset < 0 ||
274           dev->checkpointByteOffset >= dev->nDataBytesPerChunk)
275            ok = yaffs_CheckpointFlushBuffer(dev);
276
277    }
278
279    return i;
280}
281
282int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
283{
284    int i=0;
285    int ok = 1;
286    yaffs_ExtendedTags tags;
287
288
289    int chunk;
290    int realignedChunk;
291
292    __u8 *dataBytes = (__u8 *)data;
293
294    if(!dev->checkpointBuffer)
295        return 0;
296
297    if(dev->checkpointOpenForWrite)
298        return -1;
299
300    while(i < nBytes && ok) {
301
302
303        if(dev->checkpointByteOffset < 0 ||
304           dev->checkpointByteOffset >= dev->nDataBytesPerChunk) {
305
306               if(dev->checkpointCurrentBlock < 0){
307                yaffs_CheckpointFindNextCheckpointBlock(dev);
308                dev->checkpointCurrentChunk = 0;
309            }
310
311            if(dev->checkpointCurrentBlock < 0)
312                ok = 0;
313            else {
314
315                chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock +
316                          dev->checkpointCurrentChunk;
317
318                realignedChunk = chunk - dev->chunkOffset;
319
320                   /* read in the next chunk */
321                   /* printf("read checkpoint page %d\n",dev->checkpointPage); */
322                dev->readChunkWithTagsFromNAND(dev, realignedChunk,
323                                   dev->checkpointBuffer,
324                                  &tags);
325
326                if(tags.chunkId != (dev->checkpointPageSequence + 1) ||
327                   tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA)
328                   ok = 0;
329
330                dev->checkpointByteOffset = 0;
331                dev->checkpointPageSequence++;
332                dev->checkpointCurrentChunk++;
333
334                if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock)
335                    dev->checkpointCurrentBlock = -1;
336            }
337        }
338
339        if(ok){
340            *dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset];
341            dev->checkpointSum += *dataBytes;
342            dev->checkpointXor ^= *dataBytes;
343            dev->checkpointByteOffset++;
344            i++;
345            dataBytes++;
346            dev->checkpointByteCount++;
347        }
348    }
349
350    return i;
351}
352
353int yaffs_CheckpointClose(yaffs_Device *dev)
354{
355
356    if(dev->checkpointOpenForWrite){
357        if(dev->checkpointByteOffset != 0)
358            yaffs_CheckpointFlushBuffer(dev);
359    } else {
360        int i;
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;
365            else {
366                // Todo this looks odd...
367            }
368        }
369        YFREE(dev->checkpointBlockList);
370        dev->checkpointBlockList = NULL;
371    }
372
373    dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock;
374    dev->nErasedBlocks -= dev->blocksInCheckpoint;
375
376
377    T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint byte count %d" TENDSTR),
378            dev->checkpointByteCount));
379
380    if(dev->checkpointBuffer){
381        /* free the buffer */
382        YFREE(dev->checkpointBuffer);
383        dev->checkpointBuffer = NULL;
384        return 1;
385    }
386    else
387        return 0;
388
389}
390
391int yaffs_CheckpointInvalidateStream(yaffs_Device *dev)
392{
393    /* Erase the first checksum block */
394
395    T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint invalidate"TENDSTR)));
396
397    if(!yaffs_CheckpointSpaceOk(dev))
398        return 0;
399
400    return yaffs_CheckpointErase(dev);
401}
402
403
404
405

Archive Download this file



interactive