1 ext4: fix inline data updates with checksums enabled
3 The inline data code was updating the raw inode directly; this is
4 problematic since if metadata checksums are enabled,
5 ext4_mark_inode_dirty() must be called to update the inode's checksum.
6 In addition, the jbd2 layer requires that get_write_access() be called
7 before the metadata buffer is modified. Fix both of these problems.
9 https://bugzilla.kernel.org/show_bug.cgi?id=200443
11 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
12 Cc: stable@vger.kernel.org
14 fs/ext4/inline.c | 19 +++++++++++--------
15 fs/ext4/inode.c | 16 +++++++---------
16 2 files changed, 18 insertions(+), 17 deletions(-)
18 diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
19 index e55a8bc870bd..3543fe80a3c4 100644
20 --- a/fs/ext4/inline.c
21 +++ b/fs/ext4/inline.c
22 @@ -682,6 +682,10 @@ int ext4_try_to_write_inline_data(struct address_space *mapping,
26 + ret = ext4_journal_get_write_access(handle, iloc.bh);
30 flags |= AOP_FLAG_NOFS;
32 page = grab_cache_page_write_begin(mapping, 0, flags);
33 @@ -710,7 +714,7 @@ int ext4_try_to_write_inline_data(struct address_space *mapping,
35 up_read(&EXT4_I(inode)->xattr_sem);
38 + if (handle && (ret != 1))
39 ext4_journal_stop(handle);
42 @@ -752,6 +756,7 @@ int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len,
44 ext4_write_unlock_xattr(inode, &no_expand);
46 + mark_inode_dirty(inode);
50 @@ -898,7 +903,6 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping,
55 page = grab_cache_page_write_begin(mapping, 0, flags);
58 @@ -916,6 +920,9 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping,
60 goto out_release_page;
62 + ret = ext4_journal_get_write_access(handle, iloc.bh);
64 + goto out_release_page;
66 up_read(&EXT4_I(inode)->xattr_sem);
68 @@ -936,7 +943,6 @@ int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos,
69 unsigned len, unsigned copied,
72 - int i_size_changed = 0;
75 ret = ext4_write_inline_data_end(inode, pos, len, copied, page);
76 @@ -954,10 +960,8 @@ int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos,
77 * But it's important to update i_size while still holding page lock:
78 * page writeout could otherwise come in and zero beyond i_size.
80 - if (pos+copied > inode->i_size) {
81 + if (pos+copied > inode->i_size)
82 i_size_write(inode, pos+copied);
88 @@ -967,8 +971,7 @@ int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos,
89 * ordering of page lock and transaction start for journaling
93 - mark_inode_dirty(inode);
94 + mark_inode_dirty(inode);
98 diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
99 index 7d6c10017bdf..4efe77286ecd 100644
100 --- a/fs/ext4/inode.c
101 +++ b/fs/ext4/inode.c
102 @@ -1389,9 +1389,10 @@ static int ext4_write_end(struct file *file,
103 loff_t old_size = inode->i_size;
105 int i_size_changed = 0;
106 + int inline_data = ext4_has_inline_data(inode);
108 trace_ext4_write_end(inode, pos, len, copied);
109 - if (ext4_has_inline_data(inode)) {
111 ret = ext4_write_inline_data_end(inode, pos, len,
114 @@ -1419,7 +1420,7 @@ static int ext4_write_end(struct file *file,
115 * ordering of page lock and transaction start for journaling
118 - if (i_size_changed)
119 + if (i_size_changed || inline_data)
120 ext4_mark_inode_dirty(handle, inode);
122 if (pos + len > inode->i_size && ext4_can_truncate(inode))
123 @@ -1493,6 +1494,7 @@ static int ext4_journalled_write_end(struct file *file,
126 int size_changed = 0;
127 + int inline_data = ext4_has_inline_data(inode);
129 trace_ext4_journalled_write_end(inode, pos, len, copied);
130 from = pos & (PAGE_SIZE - 1);
131 @@ -1500,7 +1502,7 @@ static int ext4_journalled_write_end(struct file *file,
133 BUG_ON(!ext4_handle_valid(handle));
135 - if (ext4_has_inline_data(inode)) {
137 ret = ext4_write_inline_data_end(inode, pos, len,
140 @@ -1531,7 +1533,7 @@ static int ext4_journalled_write_end(struct file *file,
142 pagecache_isize_extended(inode, old_size, pos);
144 - if (size_changed) {
145 + if (size_changed || inline_data) {
146 ret2 = ext4_mark_inode_dirty(handle, inode);
149 @@ -2028,11 +2030,7 @@ static int __ext4_journalled_writepage(struct page *page,
153 - BUFFER_TRACE(inode_bh, "get write access");
154 - ret = ext4_journal_get_write_access(handle, inode_bh);
156 - err = ext4_handle_dirty_metadata(handle, inode, inode_bh);
158 + ret = ext4_mark_inode_dirty(handle, inode);
160 ret = ext4_walk_page_buffers(handle, page_bufs, 0, len, NULL,
161 do_journal_get_write_access);