Skip to content

Commit 90410bc

Browse files
Jan Kara via Ocfs2-develakpm00
authored andcommitted
ocfs2: fix data corruption after failed write
When buffered write fails to copy data into underlying page cache page, ocfs2_write_end_nolock() just zeroes out and dirties the page. This can leave dirty page beyond EOF and if page writeback tries to write this page before write succeeds and expands i_size, page gets into inconsistent state where page dirty bit is clear but buffer dirty bits stay set resulting in page data never getting written and so data copied to the page is lost. Fix the problem by invalidating page beyond EOF after failed write. Link: https://lkml.kernel.org/r/[email protected] Fixes: 6dbf7bb ("fs: Don't invalidate page buffers in block_write_full_page()") Signed-off-by: Jan Kara <[email protected]> Reviewed-by: Joseph Qi <[email protected]> Cc: Mark Fasheh <[email protected]> Cc: Joel Becker <[email protected]> Cc: Junxiao Bi <[email protected]> Cc: Changwei Ge <[email protected]> Cc: Gang He <[email protected]> Cc: Jun Piao <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 2ef7dbb commit 90410bc

File tree

1 file changed

+17
-2
lines changed

1 file changed

+17
-2
lines changed

fs/ocfs2/aops.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1977,11 +1977,26 @@ int ocfs2_write_end_nolock(struct address_space *mapping,
19771977
}
19781978

19791979
if (unlikely(copied < len) && wc->w_target_page) {
1980+
loff_t new_isize;
1981+
19801982
if (!PageUptodate(wc->w_target_page))
19811983
copied = 0;
19821984

1983-
ocfs2_zero_new_buffers(wc->w_target_page, start+copied,
1984-
start+len);
1985+
new_isize = max_t(loff_t, i_size_read(inode), pos + copied);
1986+
if (new_isize > page_offset(wc->w_target_page))
1987+
ocfs2_zero_new_buffers(wc->w_target_page, start+copied,
1988+
start+len);
1989+
else {
1990+
/*
1991+
* When page is fully beyond new isize (data copy
1992+
* failed), do not bother zeroing the page. Invalidate
1993+
* it instead so that writeback does not get confused
1994+
* put page & buffer dirty bits into inconsistent
1995+
* state.
1996+
*/
1997+
block_invalidate_folio(page_folio(wc->w_target_page),
1998+
0, PAGE_SIZE);
1999+
}
19852000
}
19862001
if (wc->w_target_page)
19872002
flush_dcache_page(wc->w_target_page);

0 commit comments

Comments
 (0)