| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
| From: Eric Biggers <ebiggers@google.com> |
| Date: Fri, 24 Jul 2020 18:44:58 +0000 |
| Subject: ANDROID: 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. |
| |
| [CPNOTE: 25/05/21] Lee: No update since v8 was posted in January - poked the MLs |
| [CPNOTE: 26/05/21] Lee: Satya will work to push these forward over the next week |
| [CPNOTE: 22/07/21] Lee: v9 was posted 7 weeks ago with no reviews - poked again |
| [CPNOTE: 04/08/21] Lee: Eric and Satya are still working on this [0] |
| |
| [0] https://lore.kernel.org/linux-xfs/YPmFSw4JbWnIozSZ@gmail.com/ |
| |
| Signed-off-by: Eric Biggers <ebiggers@google.com> |
| Co-developed-by: Satya Tangirala <satyat@google.com> |
| Signed-off-by: Satya Tangirala <satyat@google.com> |
| Reviewed-by: Jaegeuk Kim <jaegeuk@kernel.org> |
| |
| Bug: 162255927 |
| Link: https://lore.kernel.org/r/20200724184501.1651378-5-satyat@google.com |
| Change-Id: Ia3d869cefabdff070f4e77c46190351f6cb5d74c |
| Signed-off-by: Eric Biggers <ebiggers@google.com> |
| --- |
| 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 |
| --- 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 |
| @@ -511,7 +513,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 |
| --- a/fs/ext4/inode.c |
| +++ b/fs/ext4/inode.c |
| @@ -3444,6 +3444,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; |