From 328a492ae5c5d0e2943b73c0fda4921f180656da Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 24 Jul 2020 18:44:58 +0000 Subject: [PATCH] FROMLIST: ext4: support direct I/O with fscrypt using blk-crypto Wire up ext4 with fscrypt direct I/O support. Direct I/O with fscrypt is only supported through blk-crypto (i.e. CONFIG_BLK_INLINE_ENCRYPTION must have been enabled, the 'inlinecrypt' mount option must have been specified, and either hardware inline encryption support must be present or CONFIG_BLK_INLINE_ENCYRPTION_FALLBACK must have been enabled). Further, direct I/O on encrypted files is only supported when I/O is aligned to the filesystem block size (which is *not* necessarily the same as the block device's block size). fscrypt_limit_io_blocks() is called before setting up the iomap to ensure that the blocks of each bio that iomap will submit will have contiguous DUNs. Note that fscrypt_limit_io_blocks() is normally a no-op, as normally the DUNs simply increment along with the logical blocks. But it's needed to handle an edge case in one of the fscrypt IV generation methods. Signed-off-by: Eric Biggers Co-developed-by: Satya Tangirala Signed-off-by: Satya Tangirala Reviewed-by: Jaegeuk Kim Bug: 162255927 Link: https://lore.kernel.org/r/20200724184501.1651378-5-satyat@google.com Change-Id: Ia3d869cefabdff070f4e77c46190351f6cb5d74c Signed-off-by: Eric Biggers --- fs/ext4/file.c | 10 ++++++---- fs/ext4/inode.c | 8 ++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 194f5d00fa32..fcd097cef319 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -36,9 +36,11 @@ #include "acl.h" #include "truncate.h" -static bool ext4_dio_supported(struct inode *inode) +static bool ext4_dio_supported(struct kiocb *iocb, struct iov_iter *iter) { - if (IS_ENABLED(CONFIG_FS_ENCRYPTION) && IS_ENCRYPTED(inode)) + struct inode *inode = file_inode(iocb->ki_filp); + + if (!fscrypt_dio_supported(iocb, iter)) return false; if (fsverity_active(inode)) return false; @@ -61,7 +63,7 @@ static ssize_t ext4_dio_read_iter(struct kiocb *iocb, struct iov_iter *to) inode_lock_shared(inode); } - if (!ext4_dio_supported(inode)) { + if (!ext4_dio_supported(iocb, to)) { inode_unlock_shared(inode); /* * Fallback to buffered I/O if the operation being performed on @@ -494,7 +496,7 @@ static ssize_t ext4_dio_write_iter(struct kiocb *iocb, struct iov_iter *from) } /* Fallback to buffered I/O if the inode does not support direct I/O. */ - if (!ext4_dio_supported(inode)) { + if (!ext4_dio_supported(iocb, from)) { if (ilock_shared) inode_unlock_shared(inode); else diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 62437c900607..380a7f6a9635 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -3506,6 +3506,14 @@ static int ext4_iomap_begin(struct inode *inode, loff_t offset, loff_t length, if (ret < 0) return ret; out: + + /* + * When inline encryption is enabled, sometimes I/O to an encrypted file + * has to be broken up to guarantee DUN contiguity. Handle this by + * limiting the length of the mapping returned. + */ + map.m_len = fscrypt_limit_io_blocks(inode, map.m_lblk, map.m_len); + ext4_set_iomap(inode, iomap, &map, offset, length); return 0;