aboutsummaryrefslogtreecommitdiffstats
path: root/fs/buffer.c
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2011-06-13 18:58:27 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2011-06-16 11:44:46 -0400
commitf9f07b6c1372b1436aa6b45333445b443ffd8c95 (patch)
treeb8bd034260b2c1eee2ca585397ee598079ac261b /fs/buffer.c
parent5e7f23373bf9a853e9256e81e86724cdd0a33c29 (diff)
vfs: Fix data corruption after failed write in __block_write_begin()
I've got a report of a file corruption from fsxlinux on ext3. The important operations to the page were: mapwrite to a hole partial write to the page read - found the page zeroed from the end of the normal write The culprit seems to be that if get_block() fails in __block_write_begin() (e.g. transient ENOSPC in ext3), the function does ClearPageUptodate(page). Thus when we retry the write, the logic in __block_write_begin() thinks zeroing of the page is needed and overwrites old data. In fact, I don't see why we should ever need to zero the uptodate bit here - either the page was uptodate when we entered __block_write_begin() and it should stay so when we leave it, or it was not uptodate and noone had right to set it uptodate during __block_write_begin() so it remains !uptodate when we leave as well. So just remove clearing of the bit. Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/buffer.c')
-rw-r--r--fs/buffer.c4
1 files changed, 1 insertions, 3 deletions
diff --git a/fs/buffer.c b/fs/buffer.c
index 49c9aada0374..1a80b048ade8 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1902,10 +1902,8 @@ int __block_write_begin(struct page *page, loff_t pos, unsigned len,
1902 if (!buffer_uptodate(*wait_bh)) 1902 if (!buffer_uptodate(*wait_bh))
1903 err = -EIO; 1903 err = -EIO;
1904 } 1904 }
1905 if (unlikely(err)) { 1905 if (unlikely(err))
1906 page_zero_new_buffers(page, from, to); 1906 page_zero_new_buffers(page, from, to);
1907 ClearPageUptodate(page);
1908 }
1909 return err; 1907 return err;
1910} 1908}
1911EXPORT_SYMBOL(__block_write_begin); 1909EXPORT_SYMBOL(__block_write_begin);