1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2002-2011 Aleph One Ltd.
5*4882a593Smuzhiyun * for Toby Churchill Ltd and Brightstar Engineering
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Created by Charles Manning <charles@aleph1.co.uk>
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * This program is free software; you can redistribute it and/or modify
10*4882a593Smuzhiyun * it under the terms of the GNU General Public License version 2 as
11*4882a593Smuzhiyun * published by the Free Software Foundation.
12*4882a593Smuzhiyun */
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #include "yaffs_checkptrw.h"
15*4882a593Smuzhiyun #include "yaffs_getblockinfo.h"
16*4882a593Smuzhiyun
yaffs2_checkpt_space_ok(struct yaffs_dev * dev)17*4882a593Smuzhiyun static int yaffs2_checkpt_space_ok(struct yaffs_dev *dev)
18*4882a593Smuzhiyun {
19*4882a593Smuzhiyun int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun yaffs_trace(YAFFS_TRACE_CHECKPOINT,
22*4882a593Smuzhiyun "checkpt blocks_avail = %d", blocks_avail);
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun return (blocks_avail <= 0) ? 0 : 1;
25*4882a593Smuzhiyun }
26*4882a593Smuzhiyun
yaffs_checkpt_erase(struct yaffs_dev * dev)27*4882a593Smuzhiyun static int yaffs_checkpt_erase(struct yaffs_dev *dev)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun int i;
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun if (!dev->param.erase_fn)
32*4882a593Smuzhiyun return 0;
33*4882a593Smuzhiyun yaffs_trace(YAFFS_TRACE_CHECKPOINT,
34*4882a593Smuzhiyun "checking blocks %d to %d",
35*4882a593Smuzhiyun dev->internal_start_block, dev->internal_end_block);
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
38*4882a593Smuzhiyun struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
39*4882a593Smuzhiyun if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
40*4882a593Smuzhiyun yaffs_trace(YAFFS_TRACE_CHECKPOINT,
41*4882a593Smuzhiyun "erasing checkpt block %d", i);
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun dev->n_erasures++;
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun if (dev->param.
46*4882a593Smuzhiyun erase_fn(dev,
47*4882a593Smuzhiyun i - dev->block_offset /* realign */)) {
48*4882a593Smuzhiyun bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
49*4882a593Smuzhiyun dev->n_erased_blocks++;
50*4882a593Smuzhiyun dev->n_free_chunks +=
51*4882a593Smuzhiyun dev->param.chunks_per_block;
52*4882a593Smuzhiyun } else {
53*4882a593Smuzhiyun dev->param.bad_block_fn(dev, i);
54*4882a593Smuzhiyun bi->block_state = YAFFS_BLOCK_STATE_DEAD;
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun dev->blocks_in_checkpt = 0;
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun return 1;
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun
yaffs2_checkpt_find_erased_block(struct yaffs_dev * dev)64*4882a593Smuzhiyun static void yaffs2_checkpt_find_erased_block(struct yaffs_dev *dev)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun int i;
67*4882a593Smuzhiyun int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun yaffs_trace(YAFFS_TRACE_CHECKPOINT,
70*4882a593Smuzhiyun "allocating checkpt block: erased %d reserved %d avail %d next %d ",
71*4882a593Smuzhiyun dev->n_erased_blocks, dev->param.n_reserved_blocks,
72*4882a593Smuzhiyun blocks_avail, dev->checkpt_next_block);
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun if (dev->checkpt_next_block >= 0 &&
75*4882a593Smuzhiyun dev->checkpt_next_block <= dev->internal_end_block &&
76*4882a593Smuzhiyun blocks_avail > 0) {
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
79*4882a593Smuzhiyun i++) {
80*4882a593Smuzhiyun struct yaffs_block_info *bi =
81*4882a593Smuzhiyun yaffs_get_block_info(dev, i);
82*4882a593Smuzhiyun if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
83*4882a593Smuzhiyun dev->checkpt_next_block = i + 1;
84*4882a593Smuzhiyun dev->checkpt_cur_block = i;
85*4882a593Smuzhiyun yaffs_trace(YAFFS_TRACE_CHECKPOINT,
86*4882a593Smuzhiyun "allocating checkpt block %d", i);
87*4882a593Smuzhiyun return;
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun yaffs_trace(YAFFS_TRACE_CHECKPOINT, "out of checkpt blocks");
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun dev->checkpt_next_block = -1;
94*4882a593Smuzhiyun dev->checkpt_cur_block = -1;
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun
yaffs2_checkpt_find_block(struct yaffs_dev * dev)97*4882a593Smuzhiyun static void yaffs2_checkpt_find_block(struct yaffs_dev *dev)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun int i;
100*4882a593Smuzhiyun struct yaffs_ext_tags tags;
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun yaffs_trace(YAFFS_TRACE_CHECKPOINT,
103*4882a593Smuzhiyun "find next checkpt block: start: blocks %d next %d",
104*4882a593Smuzhiyun dev->blocks_in_checkpt, dev->checkpt_next_block);
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun if (dev->blocks_in_checkpt < dev->checkpt_max_blocks)
107*4882a593Smuzhiyun for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
108*4882a593Smuzhiyun i++) {
109*4882a593Smuzhiyun int chunk = i * dev->param.chunks_per_block;
110*4882a593Smuzhiyun int realigned_chunk = chunk - dev->chunk_offset;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun dev->param.read_chunk_tags_fn(dev, realigned_chunk,
113*4882a593Smuzhiyun NULL, &tags);
114*4882a593Smuzhiyun yaffs_trace(YAFFS_TRACE_CHECKPOINT,
115*4882a593Smuzhiyun "find next checkpt block: search: block %d oid %d seq %d eccr %d",
116*4882a593Smuzhiyun i, tags.obj_id, tags.seq_number,
117*4882a593Smuzhiyun tags.ecc_result);
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun if (tags.seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA) {
120*4882a593Smuzhiyun /* Right kind of block */
121*4882a593Smuzhiyun dev->checkpt_next_block = tags.obj_id;
122*4882a593Smuzhiyun dev->checkpt_cur_block = i;
123*4882a593Smuzhiyun dev->checkpt_block_list[dev->
124*4882a593Smuzhiyun blocks_in_checkpt] = i;
125*4882a593Smuzhiyun dev->blocks_in_checkpt++;
126*4882a593Smuzhiyun yaffs_trace(YAFFS_TRACE_CHECKPOINT,
127*4882a593Smuzhiyun "found checkpt block %d", i);
128*4882a593Smuzhiyun return;
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun yaffs_trace(YAFFS_TRACE_CHECKPOINT, "found no more checkpt blocks");
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun dev->checkpt_next_block = -1;
135*4882a593Smuzhiyun dev->checkpt_cur_block = -1;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
yaffs2_checkpt_open(struct yaffs_dev * dev,int writing)138*4882a593Smuzhiyun int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun int i;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun dev->checkpt_open_write = writing;
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun /* Got the functions we need? */
145*4882a593Smuzhiyun if (!dev->param.write_chunk_tags_fn ||
146*4882a593Smuzhiyun !dev->param.read_chunk_tags_fn ||
147*4882a593Smuzhiyun !dev->param.erase_fn || !dev->param.bad_block_fn)
148*4882a593Smuzhiyun return 0;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun if (writing && !yaffs2_checkpt_space_ok(dev))
151*4882a593Smuzhiyun return 0;
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun if (!dev->checkpt_buffer)
154*4882a593Smuzhiyun dev->checkpt_buffer =
155*4882a593Smuzhiyun kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
156*4882a593Smuzhiyun if (!dev->checkpt_buffer)
157*4882a593Smuzhiyun return 0;
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun dev->checkpt_page_seq = 0;
160*4882a593Smuzhiyun dev->checkpt_byte_count = 0;
161*4882a593Smuzhiyun dev->checkpt_sum = 0;
162*4882a593Smuzhiyun dev->checkpt_xor = 0;
163*4882a593Smuzhiyun dev->checkpt_cur_block = -1;
164*4882a593Smuzhiyun dev->checkpt_cur_chunk = -1;
165*4882a593Smuzhiyun dev->checkpt_next_block = dev->internal_start_block;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun /* Erase all the blocks in the checkpoint area */
168*4882a593Smuzhiyun if (writing) {
169*4882a593Smuzhiyun memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
170*4882a593Smuzhiyun dev->checkpt_byte_offs = 0;
171*4882a593Smuzhiyun return yaffs_checkpt_erase(dev);
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun /* Set to a value that will kick off a read */
175*4882a593Smuzhiyun dev->checkpt_byte_offs = dev->data_bytes_per_chunk;
176*4882a593Smuzhiyun /* A checkpoint block list of 1 checkpoint block per 16 block is
177*4882a593Smuzhiyun * (hopefully) going to be way more than we need */
178*4882a593Smuzhiyun dev->blocks_in_checkpt = 0;
179*4882a593Smuzhiyun dev->checkpt_max_blocks =
180*4882a593Smuzhiyun (dev->internal_end_block - dev->internal_start_block) / 16 + 2;
181*4882a593Smuzhiyun dev->checkpt_block_list =
182*4882a593Smuzhiyun kmalloc(sizeof(int) * dev->checkpt_max_blocks, GFP_NOFS);
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun if (!dev->checkpt_block_list)
185*4882a593Smuzhiyun return 0;
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun for (i = 0; i < dev->checkpt_max_blocks; i++)
188*4882a593Smuzhiyun dev->checkpt_block_list[i] = -1;
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun return 1;
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun
yaffs2_get_checkpt_sum(struct yaffs_dev * dev,u32 * sum)193*4882a593Smuzhiyun int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun u32 composite_sum;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun composite_sum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xff);
198*4882a593Smuzhiyun *sum = composite_sum;
199*4882a593Smuzhiyun return 1;
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun
yaffs2_checkpt_flush_buffer(struct yaffs_dev * dev)202*4882a593Smuzhiyun static int yaffs2_checkpt_flush_buffer(struct yaffs_dev *dev)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun int chunk;
205*4882a593Smuzhiyun int realigned_chunk;
206*4882a593Smuzhiyun struct yaffs_ext_tags tags;
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun if (dev->checkpt_cur_block < 0) {
209*4882a593Smuzhiyun yaffs2_checkpt_find_erased_block(dev);
210*4882a593Smuzhiyun dev->checkpt_cur_chunk = 0;
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun if (dev->checkpt_cur_block < 0)
214*4882a593Smuzhiyun return 0;
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun tags.is_deleted = 0;
217*4882a593Smuzhiyun tags.obj_id = dev->checkpt_next_block; /* Hint to next place to look */
218*4882a593Smuzhiyun tags.chunk_id = dev->checkpt_page_seq + 1;
219*4882a593Smuzhiyun tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA;
220*4882a593Smuzhiyun tags.n_bytes = dev->data_bytes_per_chunk;
221*4882a593Smuzhiyun if (dev->checkpt_cur_chunk == 0) {
222*4882a593Smuzhiyun /* First chunk we write for the block? Set block state to
223*4882a593Smuzhiyun checkpoint */
224*4882a593Smuzhiyun struct yaffs_block_info *bi =
225*4882a593Smuzhiyun yaffs_get_block_info(dev, dev->checkpt_cur_block);
226*4882a593Smuzhiyun bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
227*4882a593Smuzhiyun dev->blocks_in_checkpt++;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun chunk =
231*4882a593Smuzhiyun dev->checkpt_cur_block * dev->param.chunks_per_block +
232*4882a593Smuzhiyun dev->checkpt_cur_chunk;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun yaffs_trace(YAFFS_TRACE_CHECKPOINT,
235*4882a593Smuzhiyun "checkpoint wite buffer nand %d(%d:%d) objid %d chId %d",
236*4882a593Smuzhiyun chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk,
237*4882a593Smuzhiyun tags.obj_id, tags.chunk_id);
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun realigned_chunk = chunk - dev->chunk_offset;
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun dev->n_page_writes++;
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun dev->param.write_chunk_tags_fn(dev, realigned_chunk,
244*4882a593Smuzhiyun dev->checkpt_buffer, &tags);
245*4882a593Smuzhiyun dev->checkpt_byte_offs = 0;
246*4882a593Smuzhiyun dev->checkpt_page_seq++;
247*4882a593Smuzhiyun dev->checkpt_cur_chunk++;
248*4882a593Smuzhiyun if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) {
249*4882a593Smuzhiyun dev->checkpt_cur_chunk = 0;
250*4882a593Smuzhiyun dev->checkpt_cur_block = -1;
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun return 1;
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun
yaffs2_checkpt_wr(struct yaffs_dev * dev,const void * data,int n_bytes)257*4882a593Smuzhiyun int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun int i = 0;
260*4882a593Smuzhiyun int ok = 1;
261*4882a593Smuzhiyun u8 *data_bytes = (u8 *) data;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun if (!dev->checkpt_buffer)
264*4882a593Smuzhiyun return 0;
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun if (!dev->checkpt_open_write)
267*4882a593Smuzhiyun return -1;
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun while (i < n_bytes && ok) {
270*4882a593Smuzhiyun dev->checkpt_buffer[dev->checkpt_byte_offs] = *data_bytes;
271*4882a593Smuzhiyun dev->checkpt_sum += *data_bytes;
272*4882a593Smuzhiyun dev->checkpt_xor ^= *data_bytes;
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun dev->checkpt_byte_offs++;
275*4882a593Smuzhiyun i++;
276*4882a593Smuzhiyun data_bytes++;
277*4882a593Smuzhiyun dev->checkpt_byte_count++;
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun if (dev->checkpt_byte_offs < 0 ||
280*4882a593Smuzhiyun dev->checkpt_byte_offs >= dev->data_bytes_per_chunk)
281*4882a593Smuzhiyun ok = yaffs2_checkpt_flush_buffer(dev);
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun return i;
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun
yaffs2_checkpt_rd(struct yaffs_dev * dev,void * data,int n_bytes)287*4882a593Smuzhiyun int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes)
288*4882a593Smuzhiyun {
289*4882a593Smuzhiyun int i = 0;
290*4882a593Smuzhiyun int ok = 1;
291*4882a593Smuzhiyun struct yaffs_ext_tags tags;
292*4882a593Smuzhiyun int chunk;
293*4882a593Smuzhiyun int realigned_chunk;
294*4882a593Smuzhiyun u8 *data_bytes = (u8 *) data;
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun if (!dev->checkpt_buffer)
297*4882a593Smuzhiyun return 0;
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun if (dev->checkpt_open_write)
300*4882a593Smuzhiyun return -1;
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun while (i < n_bytes && ok) {
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun if (dev->checkpt_byte_offs < 0 ||
305*4882a593Smuzhiyun dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) {
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun if (dev->checkpt_cur_block < 0) {
308*4882a593Smuzhiyun yaffs2_checkpt_find_block(dev);
309*4882a593Smuzhiyun dev->checkpt_cur_chunk = 0;
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun if (dev->checkpt_cur_block < 0) {
313*4882a593Smuzhiyun ok = 0;
314*4882a593Smuzhiyun break;
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun chunk = dev->checkpt_cur_block *
318*4882a593Smuzhiyun dev->param.chunks_per_block +
319*4882a593Smuzhiyun dev->checkpt_cur_chunk;
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun realigned_chunk = chunk - dev->chunk_offset;
322*4882a593Smuzhiyun dev->n_page_reads++;
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun /* read in the next chunk */
325*4882a593Smuzhiyun dev->param.read_chunk_tags_fn(dev,
326*4882a593Smuzhiyun realigned_chunk,
327*4882a593Smuzhiyun dev->checkpt_buffer,
328*4882a593Smuzhiyun &tags);
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun if (tags.chunk_id != (dev->checkpt_page_seq + 1) ||
331*4882a593Smuzhiyun tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
332*4882a593Smuzhiyun tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA) {
333*4882a593Smuzhiyun ok = 0;
334*4882a593Smuzhiyun break;
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun dev->checkpt_byte_offs = 0;
338*4882a593Smuzhiyun dev->checkpt_page_seq++;
339*4882a593Smuzhiyun dev->checkpt_cur_chunk++;
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun if (dev->checkpt_cur_chunk >=
342*4882a593Smuzhiyun dev->param.chunks_per_block)
343*4882a593Smuzhiyun dev->checkpt_cur_block = -1;
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun *data_bytes = dev->checkpt_buffer[dev->checkpt_byte_offs];
347*4882a593Smuzhiyun dev->checkpt_sum += *data_bytes;
348*4882a593Smuzhiyun dev->checkpt_xor ^= *data_bytes;
349*4882a593Smuzhiyun dev->checkpt_byte_offs++;
350*4882a593Smuzhiyun i++;
351*4882a593Smuzhiyun data_bytes++;
352*4882a593Smuzhiyun dev->checkpt_byte_count++;
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun return i;
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun
yaffs_checkpt_close(struct yaffs_dev * dev)358*4882a593Smuzhiyun int yaffs_checkpt_close(struct yaffs_dev *dev)
359*4882a593Smuzhiyun {
360*4882a593Smuzhiyun int i;
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun if (dev->checkpt_open_write) {
363*4882a593Smuzhiyun if (dev->checkpt_byte_offs != 0)
364*4882a593Smuzhiyun yaffs2_checkpt_flush_buffer(dev);
365*4882a593Smuzhiyun } else if (dev->checkpt_block_list) {
366*4882a593Smuzhiyun for (i = 0;
367*4882a593Smuzhiyun i < dev->blocks_in_checkpt &&
368*4882a593Smuzhiyun dev->checkpt_block_list[i] >= 0; i++) {
369*4882a593Smuzhiyun int blk = dev->checkpt_block_list[i];
370*4882a593Smuzhiyun struct yaffs_block_info *bi = NULL;
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun if (dev->internal_start_block <= blk &&
373*4882a593Smuzhiyun blk <= dev->internal_end_block)
374*4882a593Smuzhiyun bi = yaffs_get_block_info(dev, blk);
375*4882a593Smuzhiyun if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY)
376*4882a593Smuzhiyun bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun kfree(dev->checkpt_block_list);
379*4882a593Smuzhiyun dev->checkpt_block_list = NULL;
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun dev->n_free_chunks -=
383*4882a593Smuzhiyun dev->blocks_in_checkpt * dev->param.chunks_per_block;
384*4882a593Smuzhiyun dev->n_erased_blocks -= dev->blocks_in_checkpt;
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun yaffs_trace(YAFFS_TRACE_CHECKPOINT, "checkpoint byte count %d",
387*4882a593Smuzhiyun dev->checkpt_byte_count);
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun if (dev->checkpt_buffer) {
390*4882a593Smuzhiyun /* free the buffer */
391*4882a593Smuzhiyun kfree(dev->checkpt_buffer);
392*4882a593Smuzhiyun dev->checkpt_buffer = NULL;
393*4882a593Smuzhiyun return 1;
394*4882a593Smuzhiyun } else {
395*4882a593Smuzhiyun return 0;
396*4882a593Smuzhiyun }
397*4882a593Smuzhiyun }
398*4882a593Smuzhiyun
yaffs2_checkpt_invalidate_stream(struct yaffs_dev * dev)399*4882a593Smuzhiyun int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev)
400*4882a593Smuzhiyun {
401*4882a593Smuzhiyun /* Erase the checkpoint data */
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun yaffs_trace(YAFFS_TRACE_CHECKPOINT,
404*4882a593Smuzhiyun "checkpoint invalidate of %d blocks",
405*4882a593Smuzhiyun dev->blocks_in_checkpt);
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun return yaffs_checkpt_erase(dev);
408*4882a593Smuzhiyun }
409