diff options
| -rw-r--r-- | fs/jffs2/wbuf.c | 65 |
1 files changed, 47 insertions, 18 deletions
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index c8128069ecf0..4e583bfecf6e 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c | |||
| @@ -9,7 +9,7 @@ | |||
| 9 | * | 9 | * |
| 10 | * For licensing information, see the file 'LICENCE' in this directory. | 10 | * For licensing information, see the file 'LICENCE' in this directory. |
| 11 | * | 11 | * |
| 12 | * $Id: wbuf.c,v 1.82 2004/11/20 22:08:31 dwmw2 Exp $ | 12 | * $Id: wbuf.c,v 1.83 2005/01/24 21:24:15 hammache Exp $ |
| 13 | * | 13 | * |
| 14 | */ | 14 | */ |
| 15 | 15 | ||
| @@ -130,7 +130,10 @@ static inline void jffs2_refile_wbuf_blocks(struct jffs2_sb_info *c) | |||
| 130 | } | 130 | } |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) | 133 | #define REFILE_NOTEMPTY 0 |
| 134 | #define REFILE_ANYWAY 1 | ||
| 135 | |||
| 136 | static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, int allow_empty) | ||
| 134 | { | 137 | { |
| 135 | D1(printk("About to refile bad block at %08x\n", jeb->offset)); | 138 | D1(printk("About to refile bad block at %08x\n", jeb->offset)); |
| 136 | 139 | ||
| @@ -144,7 +147,8 @@ static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock | |||
| 144 | D1(printk("Refiling block at %08x to bad_used_list\n", jeb->offset)); | 147 | D1(printk("Refiling block at %08x to bad_used_list\n", jeb->offset)); |
| 145 | list_add(&jeb->list, &c->bad_used_list); | 148 | list_add(&jeb->list, &c->bad_used_list); |
| 146 | } else { | 149 | } else { |
| 147 | BUG(); | 150 | if (allow_empty == REFILE_NOTEMPTY) |
| 151 | BUG(); | ||
| 148 | /* It has to have had some nodes or we couldn't be here */ | 152 | /* It has to have had some nodes or we couldn't be here */ |
| 149 | D1(printk("Refiling block at %08x to erase_pending_list\n", jeb->offset)); | 153 | D1(printk("Refiling block at %08x to erase_pending_list\n", jeb->offset)); |
| 150 | list_add(&jeb->list, &c->erase_pending_list); | 154 | list_add(&jeb->list, &c->erase_pending_list); |
| @@ -179,7 +183,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
| 179 | 183 | ||
| 180 | jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; | 184 | jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; |
| 181 | 185 | ||
| 182 | jffs2_block_refile(c, jeb); | 186 | jffs2_block_refile(c, jeb, REFILE_NOTEMPTY); |
| 183 | 187 | ||
| 184 | /* Find the first node to be recovered, by skipping over every | 188 | /* Find the first node to be recovered, by skipping over every |
| 185 | node which ends before the wbuf starts, or which is obsolete. */ | 189 | node which ends before the wbuf starts, or which is obsolete. */ |
| @@ -269,12 +273,12 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
| 269 | return; | 273 | return; |
| 270 | } | 274 | } |
| 271 | if (end-start >= c->wbuf_pagesize) { | 275 | if (end-start >= c->wbuf_pagesize) { |
| 272 | /* Need to do another write immediately. This, btw, | 276 | /* Need to do another write immediately, but it's possible |
| 273 | means that we'll be writing from 'buf' and not from | 277 | that this is just because the wbuf itself is completely |
| 274 | the wbuf. Since if we're writing from the wbuf there | 278 | full, and there's nothing earlier read back from the |
| 275 | won't be more than a wbuf full of data, now will | 279 | flash. Hence 'buf' isn't necessarily what we're writing |
| 276 | there? :) */ | 280 | from. */ |
| 277 | 281 | unsigned char *rewrite_buf = buf?:c->wbuf; | |
| 278 | uint32_t towrite = (end-start) - ((end-start)%c->wbuf_pagesize); | 282 | uint32_t towrite = (end-start) - ((end-start)%c->wbuf_pagesize); |
| 279 | 283 | ||
| 280 | D1(printk(KERN_DEBUG "Write 0x%x bytes at 0x%08x in wbuf recover\n", | 284 | D1(printk(KERN_DEBUG "Write 0x%x bytes at 0x%08x in wbuf recover\n", |
| @@ -292,14 +296,15 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
| 292 | #endif | 296 | #endif |
| 293 | if (jffs2_cleanmarker_oob(c)) | 297 | if (jffs2_cleanmarker_oob(c)) |
| 294 | ret = c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen, | 298 | ret = c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen, |
| 295 | buf, NULL, c->oobinfo); | 299 | rewrite_buf, NULL, c->oobinfo); |
| 296 | else | 300 | else |
| 297 | ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, buf); | 301 | ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, rewrite_buf); |
| 298 | 302 | ||
| 299 | if (ret || retlen != towrite) { | 303 | if (ret || retlen != towrite) { |
| 300 | /* Argh. We tried. Really we did. */ | 304 | /* Argh. We tried. Really we did. */ |
| 301 | printk(KERN_CRIT "Recovery of wbuf failed due to a second write error\n"); | 305 | printk(KERN_CRIT "Recovery of wbuf failed due to a second write error\n"); |
| 302 | kfree(buf); | 306 | if (buf) |
| 307 | kfree(buf); | ||
| 303 | 308 | ||
| 304 | if (retlen) { | 309 | if (retlen) { |
| 305 | struct jffs2_raw_node_ref *raw2; | 310 | struct jffs2_raw_node_ref *raw2; |
| @@ -321,10 +326,10 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
| 321 | 326 | ||
| 322 | c->wbuf_len = (end - start) - towrite; | 327 | c->wbuf_len = (end - start) - towrite; |
| 323 | c->wbuf_ofs = ofs + towrite; | 328 | c->wbuf_ofs = ofs + towrite; |
| 324 | memcpy(c->wbuf, buf + towrite, c->wbuf_len); | 329 | memmove(c->wbuf, rewrite_buf + towrite, c->wbuf_len); |
| 325 | /* Don't muck about with c->wbuf_inodes. False positives are harmless. */ | 330 | /* Don't muck about with c->wbuf_inodes. False positives are harmless. */ |
| 326 | 331 | if (buf) | |
| 327 | kfree(buf); | 332 | kfree(buf); |
| 328 | } else { | 333 | } else { |
| 329 | /* OK, now we're left with the dregs in whichever buffer we're using */ | 334 | /* OK, now we're left with the dregs in whichever buffer we're using */ |
| 330 | if (buf) { | 335 | if (buf) { |
| @@ -547,6 +552,12 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino) | |||
| 547 | D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() padding. Not finished checking\n")); | 552 | D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() padding. Not finished checking\n")); |
| 548 | down_write(&c->wbuf_sem); | 553 | down_write(&c->wbuf_sem); |
| 549 | ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); | 554 | ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); |
| 555 | /* retry flushing wbuf in case jffs2_wbuf_recover | ||
| 556 | left some data in the wbuf */ | ||
| 557 | if (ret) | ||
| 558 | { | ||
| 559 | ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); | ||
| 560 | } | ||
| 550 | up_write(&c->wbuf_sem); | 561 | up_write(&c->wbuf_sem); |
| 551 | } else while (old_wbuf_len && | 562 | } else while (old_wbuf_len && |
| 552 | old_wbuf_ofs == c->wbuf_ofs) { | 563 | old_wbuf_ofs == c->wbuf_ofs) { |
| @@ -561,6 +572,12 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino) | |||
| 561 | down(&c->alloc_sem); | 572 | down(&c->alloc_sem); |
| 562 | down_write(&c->wbuf_sem); | 573 | down_write(&c->wbuf_sem); |
| 563 | ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); | 574 | ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); |
| 575 | /* retry flushing wbuf in case jffs2_wbuf_recover | ||
| 576 | left some data in the wbuf */ | ||
| 577 | if (ret) | ||
| 578 | { | ||
| 579 | ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); | ||
| 580 | } | ||
| 564 | up_write(&c->wbuf_sem); | 581 | up_write(&c->wbuf_sem); |
| 565 | break; | 582 | break; |
| 566 | } | 583 | } |
| @@ -580,6 +597,9 @@ int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c) | |||
| 580 | 597 | ||
| 581 | down_write(&c->wbuf_sem); | 598 | down_write(&c->wbuf_sem); |
| 582 | ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT); | 599 | ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT); |
| 600 | /* retry - maybe wbuf recover left some data in wbuf. */ | ||
| 601 | if (ret) | ||
| 602 | ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT); | ||
| 583 | up_write(&c->wbuf_sem); | 603 | up_write(&c->wbuf_sem); |
| 584 | 604 | ||
| 585 | return ret; | 605 | return ret; |
| @@ -762,9 +782,18 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig | |||
| 762 | 782 | ||
| 763 | if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) { | 783 | if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) { |
| 764 | /* At this point we have no problem, | 784 | /* At this point we have no problem, |
| 765 | c->wbuf is empty. | 785 | c->wbuf is empty. However refile nextblock to avoid |
| 786 | writing again to same address. | ||
| 766 | */ | 787 | */ |
| 767 | *retlen = donelen; | 788 | struct jffs2_eraseblock *jeb; |
| 789 | |||
| 790 | spin_lock(&c->erase_completion_lock); | ||
| 791 | |||
| 792 | jeb = &c->blocks[outvec_to / c->sector_size]; | ||
| 793 | jffs2_block_refile(c, jeb, REFILE_ANYWAY); | ||
| 794 | |||
| 795 | *retlen = 0; | ||
| 796 | spin_unlock(&c->erase_completion_lock); | ||
| 768 | goto exit; | 797 | goto exit; |
| 769 | } | 798 | } |
| 770 | 799 | ||
