ANDROID: ext4, f2fs: enable direct I/O with inline encryption

ext4 and f2fs have traditionally not supported direct I/O on encrypted
files, since it's difficult to implement with the traditional
filesystem-layer encryption.  But when inline encryption is used
instead, it's straightforward to support direct I/O, as long as the I/O
is fully filesystem-block-aligned.  Add support for it by:

- Making the two generic direct I/O implementations in the kernel,
  __blockdev_direct_IO() and iomap_dio_rw(), set the encryption context
  on bios for inline-encrypted files.  __blockdev_direct_IO() is used by
  f2fs, and was used by ext4 in kernel v5.4 and earlier.  iomap_dio_rw()
  is used by ext4 in kernel v5.5 and later.

- Making ext4 and f2fs allow direct I/O to encrypted files (rather the
  current behavior of falling back to buffered I/O) when the file is
  using inline encryption and the I/O is fully filesystem-block-aligned.

Bug: 137270441
Change-Id: I4c8f7497eb8f829d03611d24281113d68c21d4d1
Signed-off-by: Eric Biggers <ebiggers@google.com>
This commit is contained in:
Eric Biggers
2020-01-21 09:25:59 -08:00
parent 884e364601
commit 141f59b911
4 changed files with 29 additions and 6 deletions
+5
View File
@@ -24,6 +24,7 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/fscrypt.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/highmem.h>
@@ -411,6 +412,7 @@ dio_bio_alloc(struct dio *dio, struct dio_submit *sdio,
sector_t first_sector, int nr_vecs)
{
struct bio *bio;
struct inode *inode = dio->inode;
/*
* bio_alloc() is guaranteed to return a bio when allowed to sleep and
@@ -418,6 +420,9 @@ dio_bio_alloc(struct dio *dio, struct dio_submit *sdio,
*/
bio = bio_alloc(GFP_KERNEL, nr_vecs);
fscrypt_set_bio_crypt_ctx(bio, inode,
sdio->cur_page_fs_offset >> inode->i_blkbits,
GFP_KERNEL);
bio_set_dev(bio, bdev);
bio->bi_iter.bi_sector = first_sector;
bio_set_op_attrs(bio, dio->op, dio->op_flags);
+11 -5
View File
@@ -36,10 +36,16 @@
#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))
return false;
struct inode *inode = file_inode(iocb->ki_filp);
if (IS_ENABLED(CONFIG_FS_ENCRYPTION) && IS_ENCRYPTED(inode)) {
if (!fscrypt_inode_uses_inline_crypto(inode) ||
!IS_ALIGNED(iocb->ki_pos | iov_iter_alignment(iter),
i_blocksize(inode)))
return false;
}
if (fsverity_active(inode))
return false;
if (ext4_should_journal_data(inode))
@@ -61,7 +67,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
@@ -379,7 +385,7 @@ static ssize_t ext4_dio_write_iter(struct kiocb *iocb, struct iov_iter *from)
inode_lock(inode);
}
if (!ext4_dio_supported(inode)) {
if (!ext4_dio_supported(iocb, from)) {
inode_unlock(inode);
/*
* Fallback to buffered I/O if the inode does not support
+7 -1
View File
@@ -3734,7 +3734,13 @@ static inline bool f2fs_force_buffered_io(struct inode *inode,
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
int rw = iov_iter_rw(iter);
if (f2fs_post_read_required(inode))
if (IS_ENABLED(CONFIG_FS_ENCRYPTION) && f2fs_encrypted_file(inode)) {
if (!fscrypt_inode_uses_inline_crypto(inode) ||
!IS_ALIGNED(iocb->ki_pos | iov_iter_alignment(iter),
F2FS_BLKSIZE))
return true;
}
if (fsverity_active(inode))
return true;
if (f2fs_is_multi_device(sbi))
return true;
+6
View File
@@ -6,6 +6,7 @@
#include <linux/module.h>
#include <linux/compiler.h>
#include <linux/fs.h>
#include <linux/fscrypt.h>
#include <linux/iomap.h>
#include <linux/backing-dev.h>
#include <linux/uio.h>
@@ -178,11 +179,14 @@ static void
iomap_dio_zero(struct iomap_dio *dio, struct iomap *iomap, loff_t pos,
unsigned len)
{
struct inode *inode = file_inode(dio->iocb->ki_filp);
struct page *page = ZERO_PAGE(0);
int flags = REQ_SYNC | REQ_IDLE;
struct bio *bio;
bio = bio_alloc(GFP_KERNEL, 1);
fscrypt_set_bio_crypt_ctx(bio, inode, pos >> inode->i_blkbits,
GFP_KERNEL);
bio_set_dev(bio, iomap->bdev);
bio->bi_iter.bi_sector = iomap_sector(iomap, pos);
bio->bi_private = dio;
@@ -265,6 +269,8 @@ iomap_dio_bio_actor(struct inode *inode, loff_t pos, loff_t length,
}
bio = bio_alloc(GFP_KERNEL, nr_pages);
fscrypt_set_bio_crypt_ctx(bio, inode, pos >> inode->i_blkbits,
GFP_KERNEL);
bio_set_dev(bio, iomap->bdev);
bio->bi_iter.bi_sector = iomap_sector(iomap, pos);
bio->bi_write_hint = dio->iocb->ki_hint;