Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e274bd38 authored by Satya Tangirala's avatar Satya Tangirala Committed by Alistair Delva
Browse files

BACKPORT: FROMLIST: f2fs: add inline encryption support



Wire up f2fs to support inline encryption via the helper functions which
fs/crypto/ now provides.  This includes:

- Adding a mount option 'inlinecrypt' which enables inline encryption
  on encrypted files where it can be used.

- Setting the bio_crypt_ctx on bios that will be submitted to an
  inline-encrypted file.

- Not adding logically discontiguous data to bios that will be submitted
  to an inline-encrypted file.

- Not doing filesystem-layer crypto on inline-encrypted files.

Bug: 137270441
Test: tested as series; see I26aac0ac7845a9064f28bb1421eb2522828a6dec
Change-Id: I50aee94acab3cf0922bb023bcc0d450744781812
Co-developed-by: default avatarEric Biggers <ebiggers@google.com>
Signed-off-by: default avatarEric Biggers <ebiggers@google.com>
Signed-off-by: default avatarSatya Tangirala <satyat@google.com>
Link: https://patchwork.kernel.org/patch/11214785/
parent 07973695
Loading
Loading
Loading
Loading
+68 −8
Original line number Diff line number Diff line
@@ -316,6 +316,35 @@ static struct bio *__bio_alloc(struct f2fs_io_info *fio, int npages)
	return bio;
}

static int f2fs_set_bio_crypt_ctx(struct bio *bio, const struct inode *inode,
				  pgoff_t first_idx,
				  const struct f2fs_io_info *fio,
				  gfp_t gfp_mask)
{
	/*
	 * The f2fs garbage collector sets ->encrypted_page when it wants to
	 * read/write raw data without encryption.
	 */
	if (fio && fio->encrypted_page)
		return 0;

	return fscrypt_set_bio_crypt_ctx(bio, inode, first_idx, gfp_mask);
}

static bool f2fs_crypt_mergeable_bio(struct bio *bio, const struct inode *inode,
				     pgoff_t next_idx,
				     const struct f2fs_io_info *fio)
{
	/*
	 * The f2fs garbage collector sets ->encrypted_page when it wants to
	 * read/write raw data without encryption.
	 */
	if (fio && fio->encrypted_page)
		return true;

	return fscrypt_mergeable_bio(bio, inode, next_idx);
}

static inline void __submit_bio(struct f2fs_sb_info *sbi,
				struct bio *bio, enum page_type type)
{
@@ -513,6 +542,7 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
	struct bio *bio;
	struct page *page = fio->encrypted_page ?
			fio->encrypted_page : fio->page;
	int err;

	if (!f2fs_is_valid_blkaddr(fio->sbi, fio->new_blkaddr,
			fio->is_por ? META_POR : (__is_meta_io(fio) ?
@@ -525,6 +555,13 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
	/* Allocate a new bio */
	bio = __bio_alloc(fio, 1);

	err = f2fs_set_bio_crypt_ctx(bio, fio->page->mapping->host,
				     fio->page->index, fio, GFP_NOIO);
	if (err) {
		bio_put(bio);
		return err;
	}

	if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
		bio_put(bio);
		return -EFAULT;
@@ -595,14 +632,19 @@ int f2fs_merge_page_bio(struct f2fs_io_info *fio)
	trace_f2fs_submit_page_bio(page, fio);
	f2fs_trace_ios(fio, 0);

	if (bio && !page_is_mergeable(fio->sbi, bio, *fio->last_block,
						fio->new_blkaddr)) {
	if (bio && (!page_is_mergeable(fio->sbi, bio, *fio->last_block,
				       fio->new_blkaddr) ||
		    !f2fs_crypt_mergeable_bio(bio, fio->page->mapping->host,
					      fio->page->index, fio))) {
		__submit_bio(fio->sbi, bio, fio->type);
		bio = NULL;
	}
alloc_new:
	if (!bio) {
		bio = __bio_alloc(fio, BIO_MAX_PAGES);
		f2fs_set_bio_crypt_ctx(bio, fio->page->mapping->host,
				       fio->page->index, fio,
				       GFP_NOIO | __GFP_NOFAIL);
		bio_set_op_attrs(bio, fio->op, fio->op_flags);
	}

@@ -668,8 +710,11 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio)

	inc_page_count(sbi, WB_DATA_TYPE(bio_page));

	if (io->bio && !io_is_mergeable(sbi, io->bio, io, fio,
			io->last_block_in_bio, fio->new_blkaddr))
	if (io->bio &&
	    (!io_is_mergeable(sbi, io->bio, io, fio, io->last_block_in_bio,
			      fio->new_blkaddr) ||
	     !f2fs_crypt_mergeable_bio(io->bio, fio->page->mapping->host,
				       fio->page->index, fio)))
		__submit_merged_bio(io);
alloc_new:
	if (io->bio == NULL) {
@@ -681,6 +726,9 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio)
			goto skip;
		}
		io->bio = __bio_alloc(fio, BIO_MAX_PAGES);
		f2fs_set_bio_crypt_ctx(io->bio, fio->page->mapping->host,
				       fio->page->index, fio,
				       GFP_NOIO | __GFP_NOFAIL);
		io->fio = *fio;
	}

@@ -720,15 +768,23 @@ static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr,
	struct bio *bio;
	struct bio_post_read_ctx *ctx;
	unsigned int post_read_steps = 0;
	int err;

	bio = f2fs_bio_alloc(sbi, min_t(int, nr_pages, BIO_MAX_PAGES), false);
	if (!bio)
		return ERR_PTR(-ENOMEM);

	err = f2fs_set_bio_crypt_ctx(bio, inode, first_idx, NULL, GFP_NOFS);
	if (err) {
		bio_put(bio);
		return ERR_PTR(err);
	}

	f2fs_target_device(sbi, blkaddr, bio);
	bio->bi_end_io = f2fs_read_end_io;
	bio_set_op_attrs(bio, REQ_OP_READ, op_flag);

	if (f2fs_encrypted_file(inode))
	if (fscrypt_inode_uses_fs_layer_crypto(inode))
		post_read_steps |= 1 << STEP_DECRYPT;

	if (f2fs_need_verity(inode, first_idx))
@@ -1765,8 +1821,9 @@ static int f2fs_read_single_page(struct inode *inode, struct page *page,
	 * This page will go to BIO.  Do we need to send this
	 * BIO off first?
	 */
	if (bio && !page_is_mergeable(F2FS_I_SB(inode), bio,
				*last_block_in_bio, block_nr)) {
	if (bio && (!page_is_mergeable(F2FS_I_SB(inode), bio,
				       *last_block_in_bio, block_nr) ||
		    !f2fs_crypt_mergeable_bio(bio, inode, page->index, NULL))) {
submit_and_realloc:
		__f2fs_submit_read_bio(F2FS_I_SB(inode), bio, DATA);
		bio = NULL;
@@ -1906,6 +1963,9 @@ static int encrypt_one_page(struct f2fs_io_info *fio)
	/* wait for GCed page writeback via META_MAPPING */
	f2fs_wait_on_block_writeback(inode, fio->old_blkaddr);

	if (fscrypt_inode_uses_inline_crypto(inode))
		return 0;

retry_encrypt:
	fio->encrypted_page = fscrypt_encrypt_pagecache_blocks(fio->page,
							       PAGE_SIZE, 0,
@@ -2080,7 +2140,7 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
			f2fs_unlock_op(fio->sbi);
		err = f2fs_inplace_write_data(fio);
		if (err) {
			if (f2fs_encrypted_file(inode))
			if (fscrypt_inode_uses_fs_layer_crypto(inode))
				fscrypt_finalize_bounce_page(&fio->encrypted_page);
			if (PageWriteback(page))
				end_page_writeback(page);
+3 −0
Original line number Diff line number Diff line
@@ -137,6 +137,9 @@ struct f2fs_mount_info {
	int alloc_mode;			/* segment allocation policy */
	int fsync_mode;			/* fsync policy */
	bool test_dummy_encryption;	/* test dummy encryption */
#ifdef CONFIG_FS_ENCRYPTION
	bool inlinecrypt;		/* inline encryption enabled */
#endif
	block_t unusable_cap;		/* Amount of space allowed to be
					 * unusable when disabling checkpoint
					 */
+20 −0
Original line number Diff line number Diff line
@@ -137,6 +137,7 @@ enum {
	Opt_alloc,
	Opt_fsync,
	Opt_test_dummy_encryption,
	Opt_inlinecrypt,
	Opt_checkpoint_disable,
	Opt_checkpoint_disable_cap,
	Opt_checkpoint_disable_cap_perc,
@@ -199,6 +200,7 @@ static match_table_t f2fs_tokens = {
	{Opt_alloc, "alloc_mode=%s"},
	{Opt_fsync, "fsync_mode=%s"},
	{Opt_test_dummy_encryption, "test_dummy_encryption"},
	{Opt_inlinecrypt, "inlinecrypt"},
	{Opt_checkpoint_disable, "checkpoint=disable"},
	{Opt_checkpoint_disable_cap, "checkpoint=disable:%u"},
	{Opt_checkpoint_disable_cap_perc, "checkpoint=disable:%u%%"},
@@ -783,6 +785,13 @@ static int parse_options(struct super_block *sb, char *options)
			f2fs_info(sbi, "Test dummy encryption mode enabled");
#else
			f2fs_info(sbi, "Test dummy encryption mount option ignored");
#endif
			break;
		case Opt_inlinecrypt:
#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT
			F2FS_OPTION(sbi).inlinecrypt = true;
#else
			f2fs_info(sbi, "inline encryption not supported");
#endif
			break;
		case Opt_checkpoint_disable_cap_perc:
@@ -1446,6 +1455,8 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
#ifdef CONFIG_FS_ENCRYPTION
	if (F2FS_OPTION(sbi).test_dummy_encryption)
		seq_puts(seq, ",test_dummy_encryption");
	if (F2FS_OPTION(sbi).inlinecrypt)
		seq_puts(seq, ",inlinecrypt");
#endif

	if (F2FS_OPTION(sbi).alloc_mode == ALLOC_MODE_DEFAULT)
@@ -1474,6 +1485,9 @@ static void default_options(struct f2fs_sb_info *sbi)
	F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_DEFAULT;
	F2FS_OPTION(sbi).fsync_mode = FSYNC_MODE_POSIX;
	F2FS_OPTION(sbi).test_dummy_encryption = false;
#ifdef CONFIG_FS_ENCRYPTION
	F2FS_OPTION(sbi).inlinecrypt = false;
#endif
	F2FS_OPTION(sbi).s_resuid = make_kuid(&init_user_ns, F2FS_DEF_RESUID);
	F2FS_OPTION(sbi).s_resgid = make_kgid(&init_user_ns, F2FS_DEF_RESGID);

@@ -2328,6 +2342,11 @@ static void f2fs_get_ino_and_lblk_bits(struct super_block *sb,
	*lblk_bits_ret = 8 * sizeof(block_t);
}

static bool f2fs_inline_crypt_enabled(struct super_block *sb)
{
	return F2FS_OPTION(F2FS_SB(sb)).inlinecrypt;
}

static const struct fscrypt_operations f2fs_cryptops = {
	.key_prefix		= "f2fs:",
	.get_context		= f2fs_get_context,
@@ -2337,6 +2356,7 @@ static const struct fscrypt_operations f2fs_cryptops = {
	.max_namelen		= F2FS_NAME_LEN,
	.has_stable_inodes	= f2fs_has_stable_inodes,
	.get_ino_and_lblk_bits	= f2fs_get_ino_and_lblk_bits,
	.inline_crypt_enabled	= f2fs_inline_crypt_enabled,
};
#endif