summaryrefslogtreecommitdiff
path: root/fs/mpage.c
diff options
context:
space:
mode:
authorAndrea Arcangeli <andrea@suse.de>2004-07-10 19:37:57 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-07-10 19:37:57 -0700
commit8d4261a050d08359ae0d656dff3e23785da817ea (patch)
tree87e1b0f32fa1ac3edc56248fc5eb64828fdc8175 /fs/mpage.c
parent2713346cbee5b03663d0556646ebe401e117a2f0 (diff)
[PATCH] writepage fs corruption fix
Fix a data loss bug in mpage_writepages(), triggerable under extreme memory pressure on ext2, JFS, hfs and hfsplus: The bug is the marking of the bh clean despite we could still run into the "confused" path. After that the confused path really becomes confused and it writes nothing and fs corruption triggers silenty (the reugular writepage only writes bh that are marked dirty, it never attempts to submit_bh anything marked clean). The mpage-writepage code must never mark the bh clean as far as it wants to still fallback in the regular writepage which depends on the bh to be dirty (i.e. the "goto confused" path). This could only triggers with memory pressure (it also needs buffer_heads_over_limit == 0, and that is frequent under mm pressure). Thanks a lot to Chris for his fine debugging that localized the problem in the writepage code. Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/mpage.c')
-rw-r--r--fs/mpage.c17
1 files changed, 11 insertions, 6 deletions
diff --git a/fs/mpage.c b/fs/mpage.c
index a22fc8f0ba9b..ca517fc56941 100644
--- a/fs/mpage.c
+++ b/fs/mpage.c
@@ -519,6 +519,17 @@ alloc_new:
}
/*
+ * Must try to add the page before marking the buffer clean or
+ * the confused fail path above (OOM) will be very confused when
+ * it finds all bh marked clean (i.e. it will not write anything)
+ */
+ length = first_unmapped << blkbits;
+ if (bio_add_page(bio, page, length, 0) < length) {
+ bio = mpage_bio_submit(WRITE, bio);
+ goto alloc_new;
+ }
+
+ /*
* OK, we have our BIO, so we can now mark the buffers clean. Make
* sure to only clean buffers which we know we'll be writing.
*/
@@ -538,12 +549,6 @@ alloc_new:
try_to_free_buffers(page);
}
- length = first_unmapped << blkbits;
- if (bio_add_page(bio, page, length, 0) < length) {
- bio = mpage_bio_submit(WRITE, bio);
- goto alloc_new;
- }
-
BUG_ON(PageWriteback(page));
set_page_writeback(page);
unlock_page(page);