diff options
author | Estelle Hammache <estelle.hammache@st.com> | 2005-01-24 16:24:18 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@mtd.linutronix.de> | 2005-05-23 06:12:13 -0400 |
commit | 7f716cf3f9cc9dd420b9c75071559017812df6d2 (patch) | |
tree | 5f6492e6e83562d8b048dd14c3c9b844caa3845b /fs/jffs2 | |
parent | e4803c30d64391d84635061eaebfc7d66de9d6ab (diff) |
[JFFS2] Fix block refiling
- block refiling when writing directly to flash a buffer
which is bigger than wbuf
- retry cases for flushing wbuf
Signed-off-by: Estelle Hammache <estelle.hammache@st.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'fs/jffs2')
-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 | ||