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 *) ▮ 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 *) ▮ 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 --- |