diff options
Diffstat (limited to 'fs/jffs2/erase.c')
| -rw-r--r-- | fs/jffs2/erase.c | 80 |
1 files changed, 42 insertions, 38 deletions
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index a1db9180633f..25a640e566d3 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c | |||
| @@ -50,14 +50,14 @@ static void jffs2_erase_block(struct jffs2_sb_info *c, | |||
| 50 | instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL); | 50 | instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL); |
| 51 | if (!instr) { | 51 | if (!instr) { |
| 52 | printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n"); | 52 | printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n"); |
| 53 | down(&c->erase_free_sem); | 53 | mutex_lock(&c->erase_free_sem); |
| 54 | spin_lock(&c->erase_completion_lock); | 54 | spin_lock(&c->erase_completion_lock); |
| 55 | list_move(&jeb->list, &c->erase_pending_list); | 55 | list_move(&jeb->list, &c->erase_pending_list); |
| 56 | c->erasing_size -= c->sector_size; | 56 | c->erasing_size -= c->sector_size; |
| 57 | c->dirty_size += c->sector_size; | 57 | c->dirty_size += c->sector_size; |
| 58 | jeb->dirty_size = c->sector_size; | 58 | jeb->dirty_size = c->sector_size; |
| 59 | spin_unlock(&c->erase_completion_lock); | 59 | spin_unlock(&c->erase_completion_lock); |
| 60 | up(&c->erase_free_sem); | 60 | mutex_unlock(&c->erase_free_sem); |
| 61 | return; | 61 | return; |
| 62 | } | 62 | } |
| 63 | 63 | ||
| @@ -84,14 +84,14 @@ static void jffs2_erase_block(struct jffs2_sb_info *c, | |||
| 84 | if (ret == -ENOMEM || ret == -EAGAIN) { | 84 | if (ret == -ENOMEM || ret == -EAGAIN) { |
| 85 | /* Erase failed immediately. Refile it on the list */ | 85 | /* Erase failed immediately. Refile it on the list */ |
| 86 | D1(printk(KERN_DEBUG "Erase at 0x%08x failed: %d. Refiling on erase_pending_list\n", jeb->offset, ret)); | 86 | D1(printk(KERN_DEBUG "Erase at 0x%08x failed: %d. Refiling on erase_pending_list\n", jeb->offset, ret)); |
| 87 | down(&c->erase_free_sem); | 87 | mutex_lock(&c->erase_free_sem); |
| 88 | spin_lock(&c->erase_completion_lock); | 88 | spin_lock(&c->erase_completion_lock); |
| 89 | list_move(&jeb->list, &c->erase_pending_list); | 89 | list_move(&jeb->list, &c->erase_pending_list); |
| 90 | c->erasing_size -= c->sector_size; | 90 | c->erasing_size -= c->sector_size; |
| 91 | c->dirty_size += c->sector_size; | 91 | c->dirty_size += c->sector_size; |
| 92 | jeb->dirty_size = c->sector_size; | 92 | jeb->dirty_size = c->sector_size; |
| 93 | spin_unlock(&c->erase_completion_lock); | 93 | spin_unlock(&c->erase_completion_lock); |
| 94 | up(&c->erase_free_sem); | 94 | mutex_unlock(&c->erase_free_sem); |
| 95 | return; | 95 | return; |
| 96 | } | 96 | } |
| 97 | 97 | ||
| @@ -107,7 +107,7 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count) | |||
| 107 | { | 107 | { |
| 108 | struct jffs2_eraseblock *jeb; | 108 | struct jffs2_eraseblock *jeb; |
| 109 | 109 | ||
| 110 | down(&c->erase_free_sem); | 110 | mutex_lock(&c->erase_free_sem); |
| 111 | 111 | ||
| 112 | spin_lock(&c->erase_completion_lock); | 112 | spin_lock(&c->erase_completion_lock); |
| 113 | 113 | ||
| @@ -116,9 +116,9 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count) | |||
| 116 | 116 | ||
| 117 | if (!list_empty(&c->erase_complete_list)) { | 117 | if (!list_empty(&c->erase_complete_list)) { |
| 118 | jeb = list_entry(c->erase_complete_list.next, struct jffs2_eraseblock, list); | 118 | jeb = list_entry(c->erase_complete_list.next, struct jffs2_eraseblock, list); |
| 119 | list_del(&jeb->list); | 119 | list_move(&jeb->list, &c->erase_checking_list); |
| 120 | spin_unlock(&c->erase_completion_lock); | 120 | spin_unlock(&c->erase_completion_lock); |
| 121 | up(&c->erase_free_sem); | 121 | mutex_unlock(&c->erase_free_sem); |
| 122 | jffs2_mark_erased_block(c, jeb); | 122 | jffs2_mark_erased_block(c, jeb); |
| 123 | 123 | ||
| 124 | if (!--count) { | 124 | if (!--count) { |
| @@ -139,7 +139,7 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count) | |||
| 139 | jffs2_free_jeb_node_refs(c, jeb); | 139 | jffs2_free_jeb_node_refs(c, jeb); |
| 140 | list_add(&jeb->list, &c->erasing_list); | 140 | list_add(&jeb->list, &c->erasing_list); |
| 141 | spin_unlock(&c->erase_completion_lock); | 141 | spin_unlock(&c->erase_completion_lock); |
| 142 | up(&c->erase_free_sem); | 142 | mutex_unlock(&c->erase_free_sem); |
| 143 | 143 | ||
| 144 | jffs2_erase_block(c, jeb); | 144 | jffs2_erase_block(c, jeb); |
| 145 | 145 | ||
| @@ -149,12 +149,12 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count) | |||
| 149 | 149 | ||
| 150 | /* Be nice */ | 150 | /* Be nice */ |
| 151 | yield(); | 151 | yield(); |
| 152 | down(&c->erase_free_sem); | 152 | mutex_lock(&c->erase_free_sem); |
| 153 | spin_lock(&c->erase_completion_lock); | 153 | spin_lock(&c->erase_completion_lock); |
| 154 | } | 154 | } |
| 155 | 155 | ||
| 156 | spin_unlock(&c->erase_completion_lock); | 156 | spin_unlock(&c->erase_completion_lock); |
| 157 | up(&c->erase_free_sem); | 157 | mutex_unlock(&c->erase_free_sem); |
| 158 | done: | 158 | done: |
| 159 | D1(printk(KERN_DEBUG "jffs2_erase_pending_blocks completed\n")); | 159 | D1(printk(KERN_DEBUG "jffs2_erase_pending_blocks completed\n")); |
| 160 | } | 160 | } |
| @@ -162,11 +162,11 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count) | |||
| 162 | static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) | 162 | static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) |
| 163 | { | 163 | { |
| 164 | D1(printk(KERN_DEBUG "Erase completed successfully at 0x%08x\n", jeb->offset)); | 164 | D1(printk(KERN_DEBUG "Erase completed successfully at 0x%08x\n", jeb->offset)); |
| 165 | down(&c->erase_free_sem); | 165 | mutex_lock(&c->erase_free_sem); |
| 166 | spin_lock(&c->erase_completion_lock); | 166 | spin_lock(&c->erase_completion_lock); |
| 167 | list_move_tail(&jeb->list, &c->erase_complete_list); | 167 | list_move_tail(&jeb->list, &c->erase_complete_list); |
| 168 | spin_unlock(&c->erase_completion_lock); | 168 | spin_unlock(&c->erase_completion_lock); |
| 169 | up(&c->erase_free_sem); | 169 | mutex_unlock(&c->erase_free_sem); |
| 170 | /* Ensure that kupdated calls us again to mark them clean */ | 170 | /* Ensure that kupdated calls us again to mark them clean */ |
| 171 | jffs2_erase_pending_trigger(c); | 171 | jffs2_erase_pending_trigger(c); |
| 172 | } | 172 | } |
| @@ -180,26 +180,26 @@ static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock | |||
| 180 | failed too many times. */ | 180 | failed too many times. */ |
| 181 | if (!jffs2_write_nand_badblock(c, jeb, bad_offset)) { | 181 | if (!jffs2_write_nand_badblock(c, jeb, bad_offset)) { |
| 182 | /* We'd like to give this block another try. */ | 182 | /* We'd like to give this block another try. */ |
| 183 | down(&c->erase_free_sem); | 183 | mutex_lock(&c->erase_free_sem); |
| 184 | spin_lock(&c->erase_completion_lock); | 184 | spin_lock(&c->erase_completion_lock); |
| 185 | list_move(&jeb->list, &c->erase_pending_list); | 185 | list_move(&jeb->list, &c->erase_pending_list); |
| 186 | c->erasing_size -= c->sector_size; | 186 | c->erasing_size -= c->sector_size; |
| 187 | c->dirty_size += c->sector_size; | 187 | c->dirty_size += c->sector_size; |
| 188 | jeb->dirty_size = c->sector_size; | 188 | jeb->dirty_size = c->sector_size; |
| 189 | spin_unlock(&c->erase_completion_lock); | 189 | spin_unlock(&c->erase_completion_lock); |
| 190 | up(&c->erase_free_sem); | 190 | mutex_unlock(&c->erase_free_sem); |
| 191 | return; | 191 | return; |
| 192 | } | 192 | } |
| 193 | } | 193 | } |
| 194 | 194 | ||
| 195 | down(&c->erase_free_sem); | 195 | mutex_lock(&c->erase_free_sem); |
| 196 | spin_lock(&c->erase_completion_lock); | 196 | spin_lock(&c->erase_completion_lock); |
| 197 | c->erasing_size -= c->sector_size; | 197 | c->erasing_size -= c->sector_size; |
| 198 | c->bad_size += c->sector_size; | 198 | c->bad_size += c->sector_size; |
| 199 | list_move(&jeb->list, &c->bad_list); | 199 | list_move(&jeb->list, &c->bad_list); |
| 200 | c->nr_erasing_blocks--; | 200 | c->nr_erasing_blocks--; |
| 201 | spin_unlock(&c->erase_completion_lock); | 201 | spin_unlock(&c->erase_completion_lock); |
| 202 | up(&c->erase_free_sem); | 202 | mutex_unlock(&c->erase_free_sem); |
| 203 | wake_up(&c->erase_wait); | 203 | wake_up(&c->erase_wait); |
| 204 | } | 204 | } |
| 205 | 205 | ||
| @@ -350,9 +350,11 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl | |||
| 350 | break; | 350 | break; |
| 351 | } while(--retlen); | 351 | } while(--retlen); |
| 352 | c->mtd->unpoint(c->mtd, ebuf, jeb->offset, c->sector_size); | 352 | c->mtd->unpoint(c->mtd, ebuf, jeb->offset, c->sector_size); |
| 353 | if (retlen) | 353 | if (retlen) { |
| 354 | printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08tx\n", | 354 | printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08tx\n", |
| 355 | *wordebuf, jeb->offset + c->sector_size-retlen*sizeof(*wordebuf)); | 355 | *wordebuf, jeb->offset + c->sector_size-retlen*sizeof(*wordebuf)); |
| 356 | return -EIO; | ||
| 357 | } | ||
| 356 | return 0; | 358 | return 0; |
| 357 | } | 359 | } |
| 358 | do_flash_read: | 360 | do_flash_read: |
| @@ -373,10 +375,12 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl | |||
| 373 | ret = c->mtd->read(c->mtd, ofs, readlen, &retlen, ebuf); | 375 | ret = c->mtd->read(c->mtd, ofs, readlen, &retlen, ebuf); |
| 374 | if (ret) { | 376 | if (ret) { |
| 375 | printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret); | 377 | printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret); |
| 378 | ret = -EIO; | ||
| 376 | goto fail; | 379 | goto fail; |
| 377 | } | 380 | } |
| 378 | if (retlen != readlen) { | 381 | if (retlen != readlen) { |
| 379 | printk(KERN_WARNING "Short read from newly-erased block at 0x%08x. Wanted %d, got %zd\n", ofs, readlen, retlen); | 382 | printk(KERN_WARNING "Short read from newly-erased block at 0x%08x. Wanted %d, got %zd\n", ofs, readlen, retlen); |
| 383 | ret = -EIO; | ||
| 380 | goto fail; | 384 | goto fail; |
| 381 | } | 385 | } |
| 382 | for (i=0; i<readlen; i += sizeof(unsigned long)) { | 386 | for (i=0; i<readlen; i += sizeof(unsigned long)) { |
| @@ -385,6 +389,7 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl | |||
| 385 | if (*datum + 1) { | 389 | if (*datum + 1) { |
| 386 | *bad_offset += i; | 390 | *bad_offset += i; |
| 387 | printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", *datum, *bad_offset); | 391 | printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", *datum, *bad_offset); |
| 392 | ret = -EIO; | ||
| 388 | goto fail; | 393 | goto fail; |
| 389 | } | 394 | } |
| 390 | } | 395 | } |
| @@ -419,9 +424,6 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb | |||
| 419 | if (jffs2_write_nand_cleanmarker(c, jeb)) | 424 | if (jffs2_write_nand_cleanmarker(c, jeb)) |
| 420 | goto filebad; | 425 | goto filebad; |
| 421 | } | 426 | } |
| 422 | |||
| 423 | /* Everything else got zeroed before the erase */ | ||
| 424 | jeb->free_size = c->sector_size; | ||
| 425 | } else { | 427 | } else { |
| 426 | 428 | ||
| 427 | struct kvec vecs[1]; | 429 | struct kvec vecs[1]; |
| @@ -449,48 +451,50 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb | |||
| 449 | 451 | ||
| 450 | goto filebad; | 452 | goto filebad; |
| 451 | } | 453 | } |
| 452 | |||
| 453 | /* Everything else got zeroed before the erase */ | ||
| 454 | jeb->free_size = c->sector_size; | ||
| 455 | /* FIXME Special case for cleanmarker in empty block */ | ||
| 456 | jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL, c->cleanmarker_size, NULL); | ||
| 457 | } | 454 | } |
| 455 | /* Everything else got zeroed before the erase */ | ||
| 456 | jeb->free_size = c->sector_size; | ||
| 458 | 457 | ||
| 459 | down(&c->erase_free_sem); | 458 | mutex_lock(&c->erase_free_sem); |
| 460 | spin_lock(&c->erase_completion_lock); | 459 | spin_lock(&c->erase_completion_lock); |
| 460 | |||
| 461 | c->erasing_size -= c->sector_size; | 461 | c->erasing_size -= c->sector_size; |
| 462 | c->free_size += jeb->free_size; | 462 | c->free_size += c->sector_size; |
| 463 | c->used_size += jeb->used_size; | ||
| 464 | 463 | ||
| 465 | jffs2_dbg_acct_sanity_check_nolock(c,jeb); | 464 | /* Account for cleanmarker now, if it's in-band */ |
| 466 | jffs2_dbg_acct_paranoia_check_nolock(c, jeb); | 465 | if (c->cleanmarker_size && !jffs2_cleanmarker_oob(c)) |
| 466 | jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL, c->cleanmarker_size, NULL); | ||
| 467 | 467 | ||
| 468 | list_add_tail(&jeb->list, &c->free_list); | 468 | list_move_tail(&jeb->list, &c->free_list); |
| 469 | c->nr_erasing_blocks--; | 469 | c->nr_erasing_blocks--; |
| 470 | c->nr_free_blocks++; | 470 | c->nr_free_blocks++; |
| 471 | |||
| 472 | jffs2_dbg_acct_sanity_check_nolock(c, jeb); | ||
| 473 | jffs2_dbg_acct_paranoia_check_nolock(c, jeb); | ||
| 474 | |||
| 471 | spin_unlock(&c->erase_completion_lock); | 475 | spin_unlock(&c->erase_completion_lock); |
| 472 | up(&c->erase_free_sem); | 476 | mutex_unlock(&c->erase_free_sem); |
| 473 | wake_up(&c->erase_wait); | 477 | wake_up(&c->erase_wait); |
| 474 | return; | 478 | return; |
| 475 | 479 | ||
| 476 | filebad: | 480 | filebad: |
| 477 | down(&c->erase_free_sem); | 481 | mutex_lock(&c->erase_free_sem); |
| 478 | spin_lock(&c->erase_completion_lock); | 482 | spin_lock(&c->erase_completion_lock); |
| 479 | /* Stick it on a list (any list) so erase_failed can take it | 483 | /* Stick it on a list (any list) so erase_failed can take it |
| 480 | right off again. Silly, but shouldn't happen often. */ | 484 | right off again. Silly, but shouldn't happen often. */ |
| 481 | list_add(&jeb->list, &c->erasing_list); | 485 | list_move(&jeb->list, &c->erasing_list); |
| 482 | spin_unlock(&c->erase_completion_lock); | 486 | spin_unlock(&c->erase_completion_lock); |
| 483 | up(&c->erase_free_sem); | 487 | mutex_unlock(&c->erase_free_sem); |
| 484 | jffs2_erase_failed(c, jeb, bad_offset); | 488 | jffs2_erase_failed(c, jeb, bad_offset); |
| 485 | return; | 489 | return; |
| 486 | 490 | ||
| 487 | refile: | 491 | refile: |
| 488 | /* Stick it back on the list from whence it came and come back later */ | 492 | /* Stick it back on the list from whence it came and come back later */ |
| 489 | jffs2_erase_pending_trigger(c); | 493 | jffs2_erase_pending_trigger(c); |
| 490 | down(&c->erase_free_sem); | 494 | mutex_lock(&c->erase_free_sem); |
| 491 | spin_lock(&c->erase_completion_lock); | 495 | spin_lock(&c->erase_completion_lock); |
| 492 | list_add(&jeb->list, &c->erase_complete_list); | 496 | list_move(&jeb->list, &c->erase_complete_list); |
| 493 | spin_unlock(&c->erase_completion_lock); | 497 | spin_unlock(&c->erase_completion_lock); |
| 494 | up(&c->erase_free_sem); | 498 | mutex_unlock(&c->erase_free_sem); |
| 495 | return; | 499 | return; |
| 496 | } | 500 | } |
