Skip to content

Commit 75738b7

Browse files
tytsoZhengShunQian
authored andcommitted
ext4: fix inline data updates with checksums enabled
commit 362eca7 upstream. The inline data code was updating the raw inode directly; this is problematic since if metadata checksums are enabled, ext4_mark_inode_dirty() must be called to update the inode's checksum. In addition, the jbd2 layer requires that get_write_access() be called before the metadata buffer is modified. Fix both of these problems. https://bugzilla.kernel.org/show_bug.cgi?id=200443 Signed-off-by: Theodore Ts'o <[email protected]> Cc: [email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 69ef27a commit 75738b7

File tree

2 files changed

+18
-17
lines changed

2 files changed

+18
-17
lines changed

fs/ext4/inline.c

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,10 @@ int ext4_try_to_write_inline_data(struct address_space *mapping,
692692
goto convert;
693693
}
694694

695+
ret = ext4_journal_get_write_access(handle, iloc.bh);
696+
if (ret)
697+
goto out;
698+
695699
flags |= AOP_FLAG_NOFS;
696700

697701
page = grab_cache_page_write_begin(mapping, 0, flags);
@@ -720,7 +724,7 @@ int ext4_try_to_write_inline_data(struct address_space *mapping,
720724
out_up_read:
721725
up_read(&EXT4_I(inode)->xattr_sem);
722726
out:
723-
if (handle)
727+
if (handle && (ret != 1))
724728
ext4_journal_stop(handle);
725729
brelse(iloc.bh);
726730
return ret;
@@ -762,6 +766,7 @@ int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len,
762766

763767
ext4_write_unlock_xattr(inode, &no_expand);
764768
brelse(iloc.bh);
769+
mark_inode_dirty(inode);
765770
out:
766771
return copied;
767772
}
@@ -908,7 +913,6 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping,
908913
goto out;
909914
}
910915

911-
912916
page = grab_cache_page_write_begin(mapping, 0, flags);
913917
if (!page) {
914918
ret = -ENOMEM;
@@ -926,6 +930,9 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping,
926930
if (ret < 0)
927931
goto out_release_page;
928932
}
933+
ret = ext4_journal_get_write_access(handle, iloc.bh);
934+
if (ret)
935+
goto out_release_page;
929936

930937
up_read(&EXT4_I(inode)->xattr_sem);
931938
*pagep = page;
@@ -946,7 +953,6 @@ int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos,
946953
unsigned len, unsigned copied,
947954
struct page *page)
948955
{
949-
int i_size_changed = 0;
950956
int ret;
951957

952958
ret = ext4_write_inline_data_end(inode, pos, len, copied, page);
@@ -964,10 +970,8 @@ int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos,
964970
* But it's important to update i_size while still holding page lock:
965971
* page writeout could otherwise come in and zero beyond i_size.
966972
*/
967-
if (pos+copied > inode->i_size) {
973+
if (pos+copied > inode->i_size)
968974
i_size_write(inode, pos+copied);
969-
i_size_changed = 1;
970-
}
971975
unlock_page(page);
972976
page_cache_release(page);
973977

@@ -977,8 +981,7 @@ int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos,
977981
* ordering of page lock and transaction start for journaling
978982
* filesystems.
979983
*/
980-
if (i_size_changed)
981-
mark_inode_dirty(inode);
984+
mark_inode_dirty(inode);
982985

983986
return copied;
984987
}

fs/ext4/inode.c

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1175,10 +1175,11 @@ static int ext4_write_end(struct file *file,
11751175
loff_t old_size = inode->i_size;
11761176
int ret = 0, ret2;
11771177
int i_size_changed = 0;
1178+
int inline_data = ext4_has_inline_data(inode);
11781179

11791180
trace_android_fs_datawrite_end(inode, pos, len);
11801181
trace_ext4_write_end(inode, pos, len, copied);
1181-
if (ext4_has_inline_data(inode)) {
1182+
if (inline_data) {
11821183
ret = ext4_write_inline_data_end(inode, pos, len,
11831184
copied, page);
11841185
if (ret < 0) {
@@ -1206,7 +1207,7 @@ static int ext4_write_end(struct file *file,
12061207
* ordering of page lock and transaction start for journaling
12071208
* filesystems.
12081209
*/
1209-
if (i_size_changed)
1210+
if (i_size_changed || inline_data)
12101211
ext4_mark_inode_dirty(handle, inode);
12111212

12121213
if (pos + len > inode->i_size && ext4_can_truncate(inode))
@@ -1280,6 +1281,7 @@ static int ext4_journalled_write_end(struct file *file,
12801281
int partial = 0;
12811282
unsigned from, to;
12821283
int size_changed = 0;
1284+
int inline_data = ext4_has_inline_data(inode);
12831285

12841286
trace_android_fs_datawrite_end(inode, pos, len);
12851287
trace_ext4_journalled_write_end(inode, pos, len, copied);
@@ -1288,7 +1290,7 @@ static int ext4_journalled_write_end(struct file *file,
12881290

12891291
BUG_ON(!ext4_handle_valid(handle));
12901292

1291-
if (ext4_has_inline_data(inode)) {
1293+
if (inline_data) {
12921294
ret = ext4_write_inline_data_end(inode, pos, len,
12931295
copied, page);
12941296
if (ret < 0) {
@@ -1319,7 +1321,7 @@ static int ext4_journalled_write_end(struct file *file,
13191321
if (old_size < pos)
13201322
pagecache_isize_extended(inode, old_size, pos);
13211323

1322-
if (size_changed) {
1324+
if (size_changed || inline_data) {
13231325
ret2 = ext4_mark_inode_dirty(handle, inode);
13241326
if (!ret)
13251327
ret = ret2;
@@ -1817,11 +1819,7 @@ static int __ext4_journalled_writepage(struct page *page,
18171819
}
18181820

18191821
if (inline_data) {
1820-
BUFFER_TRACE(inode_bh, "get write access");
1821-
ret = ext4_journal_get_write_access(handle, inode_bh);
1822-
1823-
err = ext4_handle_dirty_metadata(handle, inode, inode_bh);
1824-
1822+
ret = ext4_mark_inode_dirty(handle, inode);
18251823
} else {
18261824
ret = ext4_walk_page_buffers(handle, page_bufs, 0, len, NULL,
18271825
do_journal_get_write_access);

0 commit comments

Comments
 (0)