erase.c (733802d974e5af42acb7cd61b16c0ce6dd03b7ed) erase.c (182ec4eee397543101a6db8906ed88727d3f7e53)
1/*
2 * JFFS2 -- Journalling Flash File System, Version 2.
3 *
4 * Copyright (C) 2001-2003 Red Hat, Inc.
5 *
6 * Created by David Woodhouse <dwmw2@infradead.org>
7 *
8 * For licensing information, see the file 'LICENCE' in this directory.

--- 10 unchanged lines hidden (view full) ---

19#include <linux/sched.h>
20#include <linux/pagemap.h>
21#include "nodelist.h"
22
23struct erase_priv_struct {
24 struct jffs2_eraseblock *jeb;
25 struct jffs2_sb_info *c;
26};
1/*
2 * JFFS2 -- Journalling Flash File System, Version 2.
3 *
4 * Copyright (C) 2001-2003 Red Hat, Inc.
5 *
6 * Created by David Woodhouse <dwmw2@infradead.org>
7 *
8 * For licensing information, see the file 'LICENCE' in this directory.

--- 10 unchanged lines hidden (view full) ---

19#include <linux/sched.h>
20#include <linux/pagemap.h>
21#include "nodelist.h"
22
23struct erase_priv_struct {
24 struct jffs2_eraseblock *jeb;
25 struct jffs2_sb_info *c;
26};
27
27
28#ifndef __ECOS
29static void jffs2_erase_callback(struct erase_info *);
30#endif
31static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset);
32static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
33static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
34static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
35

--- 30 unchanged lines hidden (view full) ---

66 memset(instr, 0, sizeof(*instr));
67
68 instr->mtd = c->mtd;
69 instr->addr = jeb->offset;
70 instr->len = c->sector_size;
71 instr->callback = jffs2_erase_callback;
72 instr->priv = (unsigned long)(&instr[1]);
73 instr->fail_addr = 0xffffffff;
28#ifndef __ECOS
29static void jffs2_erase_callback(struct erase_info *);
30#endif
31static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset);
32static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
33static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
34static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
35

--- 30 unchanged lines hidden (view full) ---

66 memset(instr, 0, sizeof(*instr));
67
68 instr->mtd = c->mtd;
69 instr->addr = jeb->offset;
70 instr->len = c->sector_size;
71 instr->callback = jffs2_erase_callback;
72 instr->priv = (unsigned long)(&instr[1]);
73 instr->fail_addr = 0xffffffff;
74
74
75 ((struct erase_priv_struct *)instr->priv)->jeb = jeb;
76 ((struct erase_priv_struct *)instr->priv)->c = c;
77
78 ret = c->mtd->erase(c->mtd, instr);
79 if (!ret)
80 return;
81
82 bad_offset = instr->fail_addr;

--- 8 unchanged lines hidden (view full) ---

91 list_add(&jeb->list, &c->erase_pending_list);
92 c->erasing_size -= c->sector_size;
93 c->dirty_size += c->sector_size;
94 jeb->dirty_size = c->sector_size;
95 spin_unlock(&c->erase_completion_lock);
96 return;
97 }
98
75 ((struct erase_priv_struct *)instr->priv)->jeb = jeb;
76 ((struct erase_priv_struct *)instr->priv)->c = c;
77
78 ret = c->mtd->erase(c->mtd, instr);
79 if (!ret)
80 return;
81
82 bad_offset = instr->fail_addr;

--- 8 unchanged lines hidden (view full) ---

91 list_add(&jeb->list, &c->erase_pending_list);
92 c->erasing_size -= c->sector_size;
93 c->dirty_size += c->sector_size;
94 jeb->dirty_size = c->sector_size;
95 spin_unlock(&c->erase_completion_lock);
96 return;
97 }
98
99 if (ret == -EROFS)
99 if (ret == -EROFS)
100 printk(KERN_WARNING "Erase at 0x%08x failed immediately: -EROFS. Is the sector locked?\n", jeb->offset);
101 else
102 printk(KERN_WARNING "Erase at 0x%08x failed immediately: errno %d\n", jeb->offset, ret);
103
104 jffs2_erase_failed(c, jeb, bad_offset);
105}
106
107void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count)

--- 84 unchanged lines hidden (view full) ---

192 spin_lock(&c->erase_completion_lock);
193 c->erasing_size -= c->sector_size;
194 c->bad_size += c->sector_size;
195 list_del(&jeb->list);
196 list_add(&jeb->list, &c->bad_list);
197 c->nr_erasing_blocks--;
198 spin_unlock(&c->erase_completion_lock);
199 wake_up(&c->erase_wait);
100 printk(KERN_WARNING "Erase at 0x%08x failed immediately: -EROFS. Is the sector locked?\n", jeb->offset);
101 else
102 printk(KERN_WARNING "Erase at 0x%08x failed immediately: errno %d\n", jeb->offset, ret);
103
104 jffs2_erase_failed(c, jeb, bad_offset);
105}
106
107void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count)

--- 84 unchanged lines hidden (view full) ---

192 spin_lock(&c->erase_completion_lock);
193 c->erasing_size -= c->sector_size;
194 c->bad_size += c->sector_size;
195 list_del(&jeb->list);
196 list_add(&jeb->list, &c->bad_list);
197 c->nr_erasing_blocks--;
198 spin_unlock(&c->erase_completion_lock);
199 wake_up(&c->erase_wait);
200}
200}
201
202#ifndef __ECOS
203static void jffs2_erase_callback(struct erase_info *instr)
204{
205 struct erase_priv_struct *priv = (void *)instr->priv;
206
207 if(instr->state != MTD_ERASE_DONE) {
208 printk(KERN_WARNING "Erase at 0x%08x finished, but state != MTD_ERASE_DONE. State is 0x%x instead.\n", instr->addr, instr->state);
209 jffs2_erase_failed(priv->c, priv->jeb, instr->fail_addr);
210 } else {
211 jffs2_erase_succeeded(priv->c, priv->jeb);
201
202#ifndef __ECOS
203static void jffs2_erase_callback(struct erase_info *instr)
204{
205 struct erase_priv_struct *priv = (void *)instr->priv;
206
207 if(instr->state != MTD_ERASE_DONE) {
208 printk(KERN_WARNING "Erase at 0x%08x finished, but state != MTD_ERASE_DONE. State is 0x%x instead.\n", instr->addr, instr->state);
209 jffs2_erase_failed(priv->c, priv->jeb, instr->fail_addr);
210 } else {
211 jffs2_erase_succeeded(priv->c, priv->jeb);
212 }
212 }
213 kfree(instr);
214}
215#endif /* !__ECOS */
216
217/* Hmmm. Maybe we should accept the extra space it takes and make
218 this a standard doubly-linked list? */
219static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
220 struct jffs2_raw_node_ref *ref, struct jffs2_eraseblock *jeb)
221{
222 struct jffs2_inode_cache *ic = NULL;
223 struct jffs2_raw_node_ref **prev;
224
225 prev = &ref->next_in_ino;
226
227 /* Walk the inode's list once, removing any nodes from this eraseblock */
228 while (1) {
229 if (!(*prev)->next_in_ino) {
213 kfree(instr);
214}
215#endif /* !__ECOS */
216
217/* Hmmm. Maybe we should accept the extra space it takes and make
218 this a standard doubly-linked list? */
219static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
220 struct jffs2_raw_node_ref *ref, struct jffs2_eraseblock *jeb)
221{
222 struct jffs2_inode_cache *ic = NULL;
223 struct jffs2_raw_node_ref **prev;
224
225 prev = &ref->next_in_ino;
226
227 /* Walk the inode's list once, removing any nodes from this eraseblock */
228 while (1) {
229 if (!(*prev)->next_in_ino) {
230 /* We're looking at the jffs2_inode_cache, which is
230 /* We're looking at the jffs2_inode_cache, which is
231 at the end of the linked list. Stash it and continue
232 from the beginning of the list */
233 ic = (struct jffs2_inode_cache *)(*prev);
234 prev = &ic->nodes;
235 continue;
231 at the end of the linked list. Stash it and continue
232 from the beginning of the list */
233 ic = (struct jffs2_inode_cache *)(*prev);
234 prev = &ic->nodes;
235 continue;
236 }
236 }
237
238 if (SECTOR_ADDR((*prev)->flash_offset) == jeb->offset) {
239 /* It's in the block we're erasing */
240 struct jffs2_raw_node_ref *this;
241
242 this = *prev;
243 *prev = this->next_in_ino;
244 this->next_in_ino = NULL;

--- 17 unchanged lines hidden (view full) ---

262 jeb->offset, jeb->offset + c->sector_size, ic->ino));
263
264 D2({
265 int i=0;
266 struct jffs2_raw_node_ref *this;
267 printk(KERN_DEBUG "After remove_node_refs_from_ino_list: \n" KERN_DEBUG);
268
269 this = ic->nodes;
237
238 if (SECTOR_ADDR((*prev)->flash_offset) == jeb->offset) {
239 /* It's in the block we're erasing */
240 struct jffs2_raw_node_ref *this;
241
242 this = *prev;
243 *prev = this->next_in_ino;
244 this->next_in_ino = NULL;

--- 17 unchanged lines hidden (view full) ---

262 jeb->offset, jeb->offset + c->sector_size, ic->ino));
263
264 D2({
265 int i=0;
266 struct jffs2_raw_node_ref *this;
267 printk(KERN_DEBUG "After remove_node_refs_from_ino_list: \n" KERN_DEBUG);
268
269 this = ic->nodes;
270
270
271 while(this) {
272 printk( "0x%08x(%d)->", ref_offset(this), ref_flags(this));
273 if (++i == 5) {
274 printk("\n" KERN_DEBUG);
275 i=0;
276 }
277 this = this->next_in_ino;
278 }

--- 6 unchanged lines hidden (view full) ---

285
286static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
287{
288 struct jffs2_raw_node_ref *ref;
289 D1(printk(KERN_DEBUG "Freeing all node refs for eraseblock offset 0x%08x\n", jeb->offset));
290 while(jeb->first_node) {
291 ref = jeb->first_node;
292 jeb->first_node = ref->next_phys;
271 while(this) {
272 printk( "0x%08x(%d)->", ref_offset(this), ref_flags(this));
273 if (++i == 5) {
274 printk("\n" KERN_DEBUG);
275 i=0;
276 }
277 this = this->next_in_ino;
278 }

--- 6 unchanged lines hidden (view full) ---

285
286static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
287{
288 struct jffs2_raw_node_ref *ref;
289 D1(printk(KERN_DEBUG "Freeing all node refs for eraseblock offset 0x%08x\n", jeb->offset));
290 while(jeb->first_node) {
291 ref = jeb->first_node;
292 jeb->first_node = ref->next_phys;
293
293
294 /* Remove from the inode-list */
295 if (ref->next_in_ino)
296 jffs2_remove_node_refs_from_ino_list(c, ref, jeb);
297 /* else it was a non-inode node or already removed, so don't bother */
298
299 jffs2_free_raw_node_ref(ref);
300 }
301 jeb->last_node = NULL;
302}
303
304static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t *bad_offset)
305{
306 void *ebuf;
307 uint32_t ofs;
308 size_t retlen;
309 int ret = -EIO;
294 /* Remove from the inode-list */
295 if (ref->next_in_ino)
296 jffs2_remove_node_refs_from_ino_list(c, ref, jeb);
297 /* else it was a non-inode node or already removed, so don't bother */
298
299 jffs2_free_raw_node_ref(ref);
300 }
301 jeb->last_node = NULL;
302}
303
304static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t *bad_offset)
305{
306 void *ebuf;
307 uint32_t ofs;
308 size_t retlen;
309 int ret = -EIO;
310
310
311 ebuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
312 if (!ebuf) {
313 printk(KERN_WARNING "Failed to allocate page buffer for verifying erase at 0x%08x. Refiling\n", jeb->offset);
314 return -EAGAIN;
315 }
316
317 D1(printk(KERN_DEBUG "Verifying erase at 0x%08x\n", jeb->offset));
318

--- 37 unchanged lines hidden (view full) ---

356 int ret;
357 uint32_t bad_offset;
358
359 switch (jffs2_block_check_erase(c, jeb, &bad_offset)) {
360 case -EAGAIN: goto refile;
361 case -EIO: goto filebad;
362 }
363
311 ebuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
312 if (!ebuf) {
313 printk(KERN_WARNING "Failed to allocate page buffer for verifying erase at 0x%08x. Refiling\n", jeb->offset);
314 return -EAGAIN;
315 }
316
317 D1(printk(KERN_DEBUG "Verifying erase at 0x%08x\n", jeb->offset));
318

--- 37 unchanged lines hidden (view full) ---

356 int ret;
357 uint32_t bad_offset;
358
359 switch (jffs2_block_check_erase(c, jeb, &bad_offset)) {
360 case -EAGAIN: goto refile;
361 case -EIO: goto filebad;
362 }
363
364 /* Write the erase complete marker */
364 /* Write the erase complete marker */
365 D1(printk(KERN_DEBUG "Writing erased marker to block at 0x%08x\n", jeb->offset));
366 bad_offset = jeb->offset;
367
368 /* Cleanmarker in oob area or no cleanmarker at all ? */
369 if (jffs2_cleanmarker_oob(c) || c->cleanmarker_size == 0) {
370
371 if (jffs2_cleanmarker_oob(c)) {
372 if (jffs2_write_nand_cleanmarker(c, jeb))

--- 21 unchanged lines hidden (view full) ---

394 goto refile;
395 }
396
397 marker.hdr_crc = cpu_to_je32(crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4));
398
399 vecs[0].iov_base = (unsigned char *) &marker;
400 vecs[0].iov_len = sizeof(marker);
401 ret = jffs2_flash_direct_writev(c, vecs, 1, jeb->offset, &retlen);
365 D1(printk(KERN_DEBUG "Writing erased marker to block at 0x%08x\n", jeb->offset));
366 bad_offset = jeb->offset;
367
368 /* Cleanmarker in oob area or no cleanmarker at all ? */
369 if (jffs2_cleanmarker_oob(c) || c->cleanmarker_size == 0) {
370
371 if (jffs2_cleanmarker_oob(c)) {
372 if (jffs2_write_nand_cleanmarker(c, jeb))

--- 21 unchanged lines hidden (view full) ---

394 goto refile;
395 }
396
397 marker.hdr_crc = cpu_to_je32(crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4));
398
399 vecs[0].iov_base = (unsigned char *) &marker;
400 vecs[0].iov_len = sizeof(marker);
401 ret = jffs2_flash_direct_writev(c, vecs, 1, jeb->offset, &retlen);
402
402
403 if (ret || retlen != sizeof(marker)) {
404 if (ret)
405 printk(KERN_WARNING "Write clean marker to block at 0x%08x failed: %d\n",
406 jeb->offset, ret);
407 else
408 printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %zd, got %zd\n",
409 jeb->offset, sizeof(marker), retlen);
410
411 jffs2_free_raw_node_ref(marker_ref);
412 goto filebad;
413 }
414
415 marker_ref->next_in_ino = NULL;
416 marker_ref->next_phys = NULL;
417 marker_ref->flash_offset = jeb->offset | REF_NORMAL;
418 marker_ref->__totlen = c->cleanmarker_size;
403 if (ret || retlen != sizeof(marker)) {
404 if (ret)
405 printk(KERN_WARNING "Write clean marker to block at 0x%08x failed: %d\n",
406 jeb->offset, ret);
407 else
408 printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %zd, got %zd\n",
409 jeb->offset, sizeof(marker), retlen);
410
411 jffs2_free_raw_node_ref(marker_ref);
412 goto filebad;
413 }
414
415 marker_ref->next_in_ino = NULL;
416 marker_ref->next_phys = NULL;
417 marker_ref->flash_offset = jeb->offset | REF_NORMAL;
418 marker_ref->__totlen = c->cleanmarker_size;
419
419
420 jeb->first_node = jeb->last_node = marker_ref;
420 jeb->first_node = jeb->last_node = marker_ref;
421
421
422 jeb->free_size = c->sector_size - c->cleanmarker_size;
423 jeb->used_size = c->cleanmarker_size;
424 jeb->dirty_size = 0;
425 jeb->wasted_size = 0;
426 }
427
428 spin_lock(&c->erase_completion_lock);
429 c->erasing_size -= c->sector_size;

--- 30 unchanged lines hidden ---
422 jeb->free_size = c->sector_size - c->cleanmarker_size;
423 jeb->used_size = c->cleanmarker_size;
424 jeb->dirty_size = 0;
425 jeb->wasted_size = 0;
426 }
427
428 spin_lock(&c->erase_completion_lock);
429 c->erasing_size -= c->sector_size;

--- 30 unchanged lines hidden ---