From mboxrd@z Thu Jan 1 00:00:00 1970 From: Jan Kara Subject: [PATCH] vfs: Fix data corruption after failed write in __block_write_begin() Date: Tue, 14 Jun 2011 00:58:27 +0200 Message-ID: <1308005907-25032-1-git-send-email-jack@suse.cz> Cc: Andrew Morton , Christoph Hellwig , Al Viro , Jan Kara To: linux-fsdevel@vger.kernel.org Return-path: Received: from cantor.suse.de ([195.135.220.2]:52182 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752193Ab1FMW6a (ORCPT ); Mon, 13 Jun 2011 18:58:30 -0400 Sender: linux-fsdevel-owner@vger.kernel.org List-ID: 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 --- fs/buffer.c | 4 +--- 1 files changed, 1 insertions(+), 3 deletions(-) I'm definitely looking for a review of this. I wouldn't like to introduce a new data-corruption-on-error-recovery while fixing one ;) diff --git a/fs/buffer.c b/fs/buffer.c index 49c9aad..1a80b04 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, if (!buffer_uptodate(*wait_bh)) err = -EIO; } - if (unlikely(err)) { + if (unlikely(err)) page_zero_new_buffers(page, from, to); - ClearPageUptodate(page); - } return err; } EXPORT_SYMBOL(__block_write_begin); -- 1.7.1