aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_aops.c
diff options
context:
space:
mode:
authorAlain Renaud <arenaud@sgi.com>2012-06-08 15:34:46 -0400
committerBen Myers <bpm@sgi.com>2012-06-14 13:28:20 -0400
commit7d0fa3ecba2f12ceef93fffe615e5dd9b50bb794 (patch)
treebf7dfdb15f52965f50390de814c7366fb423811a /fs/xfs/xfs_aops.c
parentf8f5701bdaf9134b1f90e5044a82c66324d2073f (diff)
xfs: xfs_vm_writepage clear iomap_valid when !buffer_uptodate (REV2)
On filesytems with a block size smaller than PAGE_SIZE we currently have a problem with unwritten extents. If a we have multi-block page for which an unwritten extent has been allocated, and only some of the buffers have been written to, and they are not contiguous, we can expose stale data from disk in the blocks between the writes after extent conversion. Example of a page with unwritten and real data. buffer content 0 empty b_state = 0 1 DATA b_state = 0x1023 Uptodate,Dirty,Mapped,Unwritten 2 DATA b_state = 0x1023 Uptodate,Dirty,Mapped,Unwritten 3 empty b_state = 0 4 empty b_state = 0 5 DATA b_state = 0x1023 Uptodate,Dirty,Mapped,Unwritten 6 DATA b_state = 0x1023 Uptodate,Dirty,Mapped,Unwritten 7 empty b_state = 0 Buffers 1, 2, 5, and 6 have been written to, leaving 0, 3, 4, and 7 empty. Currently buffers 1, 2, 5, and 6 are added to a single ioend, and when IO has completed, extent conversion creates a real extent from block 1 through block 6, leaving 0 and 7 unwritten. However buffers 3 and 4 were not written to disk, so stale data is exposed from those blocks on a subsequent read. Fix this by setting iomap_valid = 0 when we find a buffer that is not Uptodate. This ensures that buffers 5 and 6 are not added to the same ioend as buffers 1 and 2. Later these blocks will be converted into two separate real extents, leaving the blocks in between unwritten. Signed-off-by: Alain Renaud <arenaud@sgi.com> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_aops.c')
-rw-r--r--fs/xfs/xfs_aops.c11
1 files changed, 8 insertions, 3 deletions
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
index ae31c313a79e..8dad722c0041 100644
--- a/fs/xfs/xfs_aops.c
+++ b/fs/xfs/xfs_aops.c
@@ -981,10 +981,15 @@ xfs_vm_writepage(
981 imap_valid = 0; 981 imap_valid = 0;
982 } 982 }
983 } else { 983 } else {
984 if (PageUptodate(page)) { 984 if (PageUptodate(page))
985 ASSERT(buffer_mapped(bh)); 985 ASSERT(buffer_mapped(bh));
986 imap_valid = 0; 986 /*
987 } 987 * This buffer is not uptodate and will not be
988 * written to disk. Ensure that we will put any
989 * subsequent writeable buffers into a new
990 * ioend.
991 */
992 imap_valid = 0;
988 continue; 993 continue;
989 } 994 }
990 995