]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/2.6.32.1/0022-ext4-Avoid-data-filesystem-corruption-when-write-fai.patch
drop queue-4.14/mips-make-sure-dt-memory-regions-are-valid.patch
[thirdparty/kernel/stable-queue.git] / releases / 2.6.32.1 / 0022-ext4-Avoid-data-filesystem-corruption-when-write-fai.patch
1 From 968c53cec156cb9a3239969a3686c33a0e5cc9ab Mon Sep 17 00:00:00 2001
2 From: Jan Kara <jack@suse.cz>
3 Date: Tue, 8 Dec 2009 21:24:33 -0500
4 Subject: [PATCH 22/30] ext4: Avoid data / filesystem corruption when write fails to copy data
5
6 (cherry picked from commit b9a4207d5e911b938f73079a83cc2ae10524ec7f)
7
8 When ext4_write_begin fails after allocating some blocks or
9 generic_perform_write fails to copy data to write, we truncate blocks
10 already instantiated beyond i_size. Although these blocks were never
11 inside i_size, we have to truncate the pagecache of these blocks so
12 that corresponding buffers get unmapped. Otherwise subsequent
13 __block_prepare_write (called because we are retrying the write) will
14 find the buffers mapped, not call ->get_block, and thus the page will
15 be backed by already freed blocks leading to filesystem and data
16 corruption.
17
18 Signed-off-by: Jan Kara <jack@suse.cz>
19 Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
20 Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
21 ---
22 fs/ext4/inode.c | 20 +++++++++++++++-----
23 1 file changed, 15 insertions(+), 5 deletions(-)
24
25 --- a/fs/ext4/inode.c
26 +++ b/fs/ext4/inode.c
27 @@ -1534,6 +1534,16 @@ static int do_journal_get_write_access(h
28 return ext4_journal_get_write_access(handle, bh);
29 }
30
31 +/*
32 + * Truncate blocks that were not used by write. We have to truncate the
33 + * pagecache as well so that corresponding buffers get properly unmapped.
34 + */
35 +static void ext4_truncate_failed_write(struct inode *inode)
36 +{
37 + truncate_inode_pages(inode->i_mapping, inode->i_size);
38 + ext4_truncate(inode);
39 +}
40 +
41 static int ext4_write_begin(struct file *file, struct address_space *mapping,
42 loff_t pos, unsigned len, unsigned flags,
43 struct page **pagep, void **fsdata)
44 @@ -1599,7 +1609,7 @@ retry:
45
46 ext4_journal_stop(handle);
47 if (pos + len > inode->i_size) {
48 - ext4_truncate(inode);
49 + ext4_truncate_failed_write(inode);
50 /*
51 * If truncate failed early the inode might
52 * still be on the orphan list; we need to
53 @@ -1709,7 +1719,7 @@ static int ext4_ordered_write_end(struct
54 ret = ret2;
55
56 if (pos + len > inode->i_size) {
57 - ext4_truncate(inode);
58 + ext4_truncate_failed_write(inode);
59 /*
60 * If truncate failed early the inode might still be
61 * on the orphan list; we need to make sure the inode
62 @@ -1751,7 +1761,7 @@ static int ext4_writeback_write_end(stru
63 ret = ret2;
64
65 if (pos + len > inode->i_size) {
66 - ext4_truncate(inode);
67 + ext4_truncate_failed_write(inode);
68 /*
69 * If truncate failed early the inode might still be
70 * on the orphan list; we need to make sure the inode
71 @@ -1814,7 +1824,7 @@ static int ext4_journalled_write_end(str
72 if (!ret)
73 ret = ret2;
74 if (pos + len > inode->i_size) {
75 - ext4_truncate(inode);
76 + ext4_truncate_failed_write(inode);
77 /*
78 * If truncate failed early the inode might still be
79 * on the orphan list; we need to make sure the inode
80 @@ -3091,7 +3101,7 @@ retry:
81 * i_size_read because we hold i_mutex.
82 */
83 if (pos + len > inode->i_size)
84 - ext4_truncate(inode);
85 + ext4_truncate_failed_write(inode);
86 }
87
88 if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))