1 ext4 crypto: fix bugs in ext4_encrypted_zeroout()
3 Fix multiple bugs in ext4_encrypted_zeroout(), including one that
4 could cause us to write an encrypted zero page to the wrong location
5 on disk, potentially causing data and file system corruption.
6 Fortunately, this tends to only show up in stress tests, but even with
7 these fixes, we are seeing some test failures with generic/127 --- but
8 these are now caused by data failures instead of metadata corruption.
10 Since ext4_encrypted_zeroout() is only used for some optimizations to
11 keep the extent tree from being too fragmented, and
12 ext4_encrypted_zeroout() itself isn't all that optimized from a time
13 or IOPS perspective, disable the extent tree optimization for
14 encrypted inodes for now. This prevents the data corruption issues
15 reported by generic/127 until we can figure out what's going wrong.
17 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
18 Cc: stable@vger.kernel.org
20 fs/ext4/crypto.c | 23 +++++++++++++++++++----
21 fs/ext4/extents.c | 3 +++
22 2 files changed, 22 insertions(+), 4 deletions(-)
24 diff --git a/fs/ext4/crypto.c b/fs/ext4/crypto.c
25 index 3a5a7a2..b4bb1f8 100644
26 --- a/fs/ext4/crypto.c
27 +++ b/fs/ext4/crypto.c
28 @@ -393,7 +393,13 @@ int ext4_encrypted_zeroout(struct inode *inode, struct ext4_extent *ex)
29 ext4_lblk_t lblk = ex->ee_block;
30 ext4_fsblk_t pblk = ext4_ext_pblock(ex);
31 unsigned int len = ext4_ext_get_actual_len(ex);
36 + ext4_msg(inode->i_sb, KERN_CRIT,
37 + "ext4_encrypted_zeroout ino %lu lblk %u len %u",
38 + (unsigned long) inode->i_ino, lblk, len);
41 BUG_ON(inode->i_sb->s_blocksize != PAGE_CACHE_SIZE);
43 @@ -419,17 +425,26 @@ int ext4_encrypted_zeroout(struct inode *inode, struct ext4_extent *ex)
46 bio->bi_bdev = inode->i_sb->s_bdev;
47 - bio->bi_iter.bi_sector = pblk;
48 - err = bio_add_page(bio, ciphertext_page,
49 + bio->bi_iter.bi_sector =
50 + pblk << (inode->i_sb->s_blocksize_bits - 9);
51 + ret = bio_add_page(bio, ciphertext_page,
52 inode->i_sb->s_blocksize, 0);
54 + if (ret != inode->i_sb->s_blocksize) {
55 + /* should never happen! */
56 + ext4_msg(inode->i_sb, KERN_ERR,
57 + "bio_add_page failed: %d", ret);
63 err = submit_bio_wait(WRITE, bio);
64 + if ((err == 0) && bio->bi_error)
73 diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
74 index 2553aa8..7f486e3 100644
75 --- a/fs/ext4/extents.c
76 +++ b/fs/ext4/extents.c
77 @@ -3558,6 +3558,9 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
78 max_zeroout = sbi->s_extent_max_zeroout_kb >>
79 (inode->i_sb->s_blocksize_bits - 10);
81 + if (ext4_encrypted_inode(inode))
84 /* If extent is less than s_max_zeroout_kb, zeroout directly */
85 if (max_zeroout && (ee_len <= max_zeroout)) {
86 err = ext4_ext_zeroout(inode, ex);