* [PATCH 00/16] fscrypt: Standardize on blk-crypto
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
0 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: linux-fsdevel, linux-ext4, linux-f2fs-devel, linux-block,
Christoph Hellwig, Theodore Ts'o, Andreas Dilger, Baokun Li,
Jan Kara, Ojaswin Mujoo, Ritesh Harjani, Zhang Yi, Jaegeuk Kim,
Chao Yu, Eric Biggers
This series can also be retrieved from:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git/ fscrypt-blk-crypto-v1
Currently, ext4 and f2fs (i.e., the block-based filesystems with fscrypt
support) have two file contents encryption implementations:
- Filesystem-layer, where code in fs/crypto/ directly invokes
crypto_skcipher to en/decrypt data using the CPU. This
implementation requires the management of bounce pages at the
filesystem level. It doesn't support direct I/O or large folios.
- blk-crypto (also known as inline encryption), where the filesystem
assigns bio_crypt_ctxs to bios, which are then processed either by
the CPU using blk-crypto-fallback.c or by inline encryption hardware.
This supports direct I/O and is compatible with large folios.
Currently, the latter implementation is enabled only when the
"inlinecrypt" mount option is given.
The persistence of the fs-layer implementation is mainly for historical
reasons, as it came first. It's becoming increasingly hard to maintain,
especially as the filesystems get refactored to use iomap, large folios,
etc. It's time to remove it and just rely on the similar code in
blk-crypto-fallback. This series does that.
Some fs-layer encryption support remains in fs/crypto/ for non-block
based filesystems (UBIFS and CephFS), as well as directories and
symlinks. So it's not entirely gone, but it's reduced.
To be clear, this just changes an internal implementation detail. ext4
and f2fs continue to fully support encryption (fscrypt), regardless of
the presence of inline encryption hardware on the system.
Eric Biggers (16):
blk-crypto: Simplify check for fallback support
blk-crypto: Fold __blk_crypto_cfg_supported() into its caller
blk-crypto: Allow control over whether hardware is used
fscrypt: Fully disallow IV_INO_LBLK_32 with s_blocksize != PAGE_SIZE
fscrypt: Always use blk-crypto for contents on block-based filesystems
ext4: Remove fs-layer file contents en/decryption code
ext4: Make ext4_bio_write_folio() return void
ext4: Further de-generalize the bio postprocessing code
f2fs: Remove fs-layer file contents en/decryption code
fs/buffer: Remove fs-layer decryption code
fscrypt: Replace calls to fscrypt_inode_uses_inline_crypto()
fscrypt: Remove fscrypt_dio_supported()
fscrypt: Remove fs-layer zeroout code
fscrypt: Remove unused functions and workqueue
fscrypt: Merge bio.c and inline_crypt.c into block.c
fscrypt: Add safety checks to non-block-based en/decryption
Documentation/filesystems/fscrypt.rst | 39 ++-
arch/loongarch/configs/loongson32_defconfig | 1 -
arch/loongarch/configs/loongson64_defconfig | 1 -
block/blk-crypto-fallback.c | 3 +-
block/blk-crypto-profile.c | 22 --
block/blk-crypto.c | 31 ++-
drivers/md/dm-inlinecrypt.c | 2 +-
fs/buffer.c | 45 +---
fs/crypto/Kconfig | 8 +-
fs/crypto/Makefile | 3 +-
fs/crypto/bio.c | 216 ---------------
fs/crypto/{inline_crypt.c => block.c} | 283 +++++++++-----------
fs/crypto/crypto.c | 140 ++++------
fs/crypto/fscrypt_private.h | 28 +-
fs/crypto/keysetup.c | 31 +--
fs/crypto/policy.c | 17 ++
fs/ext4/crypto.c | 2 +-
fs/ext4/ext4.h | 6 +-
fs/ext4/inode.c | 64 +----
fs/ext4/page-io.c | 74 +----
fs/ext4/readpage.c | 140 +++-------
fs/ext4/super.c | 6 +-
fs/f2fs/compress.c | 28 +-
fs/f2fs/data.c | 93 +------
fs/f2fs/f2fs.h | 2 -
fs/f2fs/file.c | 2 -
fs/f2fs/segment.c | 2 -
fs/f2fs/super.c | 2 +-
include/linux/blk-crypto.h | 6 +-
include/linux/fscrypt.h | 96 ++-----
30 files changed, 357 insertions(+), 1036 deletions(-)
delete mode 100644 fs/crypto/bio.c
rename fs/crypto/{inline_crypt.c => block.c} (61%)
base-commit: 1dc18801be29bc54709aa355b8acd80e183b03cd
prerequisite-patch-id: 319d2891e88c7df1ebb5ebf434d18b68f770399f
prerequisite-patch-id: f6157c86deab0ff5ec953ae3ed6b0e84f37741bf
prerequisite-patch-id: 5330c9e4b65644baae81bd177a46be6223d2b494
prerequisite-patch-id: 073cb85332cc58e4b5066bf8f7ac948c0d9a2bac
prerequisite-patch-id: 4b1b7521df7ce7157156dbbc373c699060b21e3f
prerequisite-patch-id: edfd2a34a97697517828f233e478e5b7f8cf85c2
--
2.54.0
^ permalink raw reply [flat|nested] 34+ messages in thread
* [f2fs-dev] [PATCH 00/16] fscrypt: Standardize on blk-crypto
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
0 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers via Linux-f2fs-devel @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: Ritesh Harjani, Theodore Ts'o, Zhang Yi, linux-f2fs-devel,
linux-block, Andreas Dilger, Ojaswin Mujoo, Baokun Li,
Jaegeuk Kim, linux-fsdevel, Jan Kara, linux-ext4,
Christoph Hellwig, Eric Biggers
This series can also be retrieved from:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git/ fscrypt-blk-crypto-v1
Currently, ext4 and f2fs (i.e., the block-based filesystems with fscrypt
support) have two file contents encryption implementations:
- Filesystem-layer, where code in fs/crypto/ directly invokes
crypto_skcipher to en/decrypt data using the CPU. This
implementation requires the management of bounce pages at the
filesystem level. It doesn't support direct I/O or large folios.
- blk-crypto (also known as inline encryption), where the filesystem
assigns bio_crypt_ctxs to bios, which are then processed either by
the CPU using blk-crypto-fallback.c or by inline encryption hardware.
This supports direct I/O and is compatible with large folios.
Currently, the latter implementation is enabled only when the
"inlinecrypt" mount option is given.
The persistence of the fs-layer implementation is mainly for historical
reasons, as it came first. It's becoming increasingly hard to maintain,
especially as the filesystems get refactored to use iomap, large folios,
etc. It's time to remove it and just rely on the similar code in
blk-crypto-fallback. This series does that.
Some fs-layer encryption support remains in fs/crypto/ for non-block
based filesystems (UBIFS and CephFS), as well as directories and
symlinks. So it's not entirely gone, but it's reduced.
To be clear, this just changes an internal implementation detail. ext4
and f2fs continue to fully support encryption (fscrypt), regardless of
the presence of inline encryption hardware on the system.
Eric Biggers (16):
blk-crypto: Simplify check for fallback support
blk-crypto: Fold __blk_crypto_cfg_supported() into its caller
blk-crypto: Allow control over whether hardware is used
fscrypt: Fully disallow IV_INO_LBLK_32 with s_blocksize != PAGE_SIZE
fscrypt: Always use blk-crypto for contents on block-based filesystems
ext4: Remove fs-layer file contents en/decryption code
ext4: Make ext4_bio_write_folio() return void
ext4: Further de-generalize the bio postprocessing code
f2fs: Remove fs-layer file contents en/decryption code
fs/buffer: Remove fs-layer decryption code
fscrypt: Replace calls to fscrypt_inode_uses_inline_crypto()
fscrypt: Remove fscrypt_dio_supported()
fscrypt: Remove fs-layer zeroout code
fscrypt: Remove unused functions and workqueue
fscrypt: Merge bio.c and inline_crypt.c into block.c
fscrypt: Add safety checks to non-block-based en/decryption
Documentation/filesystems/fscrypt.rst | 39 ++-
arch/loongarch/configs/loongson32_defconfig | 1 -
arch/loongarch/configs/loongson64_defconfig | 1 -
block/blk-crypto-fallback.c | 3 +-
block/blk-crypto-profile.c | 22 --
block/blk-crypto.c | 31 ++-
drivers/md/dm-inlinecrypt.c | 2 +-
fs/buffer.c | 45 +---
fs/crypto/Kconfig | 8 +-
fs/crypto/Makefile | 3 +-
fs/crypto/bio.c | 216 ---------------
fs/crypto/{inline_crypt.c => block.c} | 283 +++++++++-----------
fs/crypto/crypto.c | 140 ++++------
fs/crypto/fscrypt_private.h | 28 +-
fs/crypto/keysetup.c | 31 +--
fs/crypto/policy.c | 17 ++
fs/ext4/crypto.c | 2 +-
fs/ext4/ext4.h | 6 +-
fs/ext4/inode.c | 64 +----
fs/ext4/page-io.c | 74 +----
fs/ext4/readpage.c | 140 +++-------
fs/ext4/super.c | 6 +-
fs/f2fs/compress.c | 28 +-
fs/f2fs/data.c | 93 +------
fs/f2fs/f2fs.h | 2 -
fs/f2fs/file.c | 2 -
fs/f2fs/segment.c | 2 -
fs/f2fs/super.c | 2 +-
include/linux/blk-crypto.h | 6 +-
include/linux/fscrypt.h | 96 ++-----
30 files changed, 357 insertions(+), 1036 deletions(-)
delete mode 100644 fs/crypto/bio.c
rename fs/crypto/{inline_crypt.c => block.c} (61%)
base-commit: 1dc18801be29bc54709aa355b8acd80e183b03cd
prerequisite-patch-id: 319d2891e88c7df1ebb5ebf434d18b68f770399f
prerequisite-patch-id: f6157c86deab0ff5ec953ae3ed6b0e84f37741bf
prerequisite-patch-id: 5330c9e4b65644baae81bd177a46be6223d2b494
prerequisite-patch-id: 073cb85332cc58e4b5066bf8f7ac948c0d9a2bac
prerequisite-patch-id: 4b1b7521df7ce7157156dbbc373c699060b21e3f
prerequisite-patch-id: edfd2a34a97697517828f233e478e5b7f8cf85c2
--
2.54.0
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH 01/16] blk-crypto: Simplify check for fallback support
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
-1 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: linux-fsdevel, linux-ext4, linux-f2fs-devel, linux-block,
Christoph Hellwig, Theodore Ts'o, Andreas Dilger, Baokun Li,
Jan Kara, Ojaswin Mujoo, Ritesh Harjani, Zhang Yi, Jaegeuk Kim,
Chao Yu, Eric Biggers
Since blk-crypto-fallback supports all blk_crypto_keys except wrapped
keys, just check for that condition directly instead of using
__blk_crypto_cfg_supported(). With this done,
__blk_crypto_cfg_supported() is now used only for the hardware support.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
block/blk-crypto-fallback.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/block/blk-crypto-fallback.c b/block/blk-crypto-fallback.c
index 2a5c52ab74b4..2a8f40a65158 100644
--- a/block/blk-crypto-fallback.c
+++ b/block/blk-crypto-fallback.c
@@ -494,12 +494,11 @@ bool blk_crypto_fallback_bio_prep(struct bio *bio)
/* User didn't call blk_crypto_start_using_key() first */
bio_io_error(bio);
return false;
}
- if (!__blk_crypto_cfg_supported(blk_crypto_fallback_profile,
- &bc->bc_key->crypto_cfg)) {
+ if (bc->bc_key->crypto_cfg.key_type != BLK_CRYPTO_KEY_TYPE_RAW) {
bio_endio_status(bio, BLK_STS_NOTSUPP);
return false;
}
if (bio_data_dir(bio) == WRITE) {
--
2.54.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [f2fs-dev] [PATCH 01/16] blk-crypto: Simplify check for fallback support
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
0 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers via Linux-f2fs-devel @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: Ritesh Harjani, Theodore Ts'o, Zhang Yi, linux-f2fs-devel,
linux-block, Andreas Dilger, Ojaswin Mujoo, Baokun Li,
Jaegeuk Kim, linux-fsdevel, Jan Kara, linux-ext4,
Christoph Hellwig, Eric Biggers
Since blk-crypto-fallback supports all blk_crypto_keys except wrapped
keys, just check for that condition directly instead of using
__blk_crypto_cfg_supported(). With this done,
__blk_crypto_cfg_supported() is now used only for the hardware support.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
block/blk-crypto-fallback.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/block/blk-crypto-fallback.c b/block/blk-crypto-fallback.c
index 2a5c52ab74b4..2a8f40a65158 100644
--- a/block/blk-crypto-fallback.c
+++ b/block/blk-crypto-fallback.c
@@ -494,12 +494,11 @@ bool blk_crypto_fallback_bio_prep(struct bio *bio)
/* User didn't call blk_crypto_start_using_key() first */
bio_io_error(bio);
return false;
}
- if (!__blk_crypto_cfg_supported(blk_crypto_fallback_profile,
- &bc->bc_key->crypto_cfg)) {
+ if (bc->bc_key->crypto_cfg.key_type != BLK_CRYPTO_KEY_TYPE_RAW) {
bio_endio_status(bio, BLK_STS_NOTSUPP);
return false;
}
if (bio_data_dir(bio) == WRITE) {
--
2.54.0
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 02/16] blk-crypto: Fold __blk_crypto_cfg_supported() into its caller
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
-1 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: linux-fsdevel, linux-ext4, linux-f2fs-devel, linux-block,
Christoph Hellwig, Theodore Ts'o, Andreas Dilger, Baokun Li,
Jan Kara, Ojaswin Mujoo, Ritesh Harjani, Zhang Yi, Jaegeuk Kim,
Chao Yu, Eric Biggers
__blk_crypto_cfg_supported() is called only by
blk_crypto_config_supported_natively(), so fold it in.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
block/blk-crypto-profile.c | 22 ----------------------
block/blk-crypto.c | 23 +++++++++++++++++++++--
2 files changed, 21 insertions(+), 24 deletions(-)
diff --git a/block/blk-crypto-profile.c b/block/blk-crypto-profile.c
index cf447ba4a66e..53126c091b0b 100644
--- a/block/blk-crypto-profile.c
+++ b/block/blk-crypto-profile.c
@@ -333,32 +333,10 @@ void blk_crypto_put_keyslot(struct blk_crypto_keyslot *slot)
spin_unlock_irqrestore(&profile->idle_slots_lock, flags);
wake_up(&profile->idle_slots_wait_queue);
}
}
-/**
- * __blk_crypto_cfg_supported() - Check whether the given crypto profile
- * supports the given crypto configuration.
- * @profile: the crypto profile to check
- * @cfg: the crypto configuration to check for
- *
- * Return: %true if @profile supports the given @cfg.
- */
-bool __blk_crypto_cfg_supported(struct blk_crypto_profile *profile,
- const struct blk_crypto_config *cfg)
-{
- if (!profile)
- return false;
- if (!(profile->modes_supported[cfg->crypto_mode] & cfg->data_unit_size))
- return false;
- if (profile->max_dun_bytes_supported < cfg->dun_bytes)
- return false;
- if (!(profile->key_types_supported & cfg->key_type))
- return false;
- return true;
-}
-
/*
* This is an internal function that evicts a key from an inline encryption
* device that can be either a real device or the blk-crypto-fallback "device".
* It is used only by blk_crypto_evict_key(); see that function for details.
*/
diff --git a/block/blk-crypto.c b/block/blk-crypto.c
index 15e25e41b166..dd83fc5af282 100644
--- a/block/blk-crypto.c
+++ b/block/blk-crypto.c
@@ -349,15 +349,34 @@ int blk_crypto_init_key(struct blk_crypto_key *blk_key,
return 0;
}
EXPORT_SYMBOL_GPL(blk_crypto_init_key);
+
+/**
+ * blk_crypto_config_supported_natively() - Check whether a block device
+ * supports hardware inline encryption
+ * with the given configuration.
+ * @bdev: the block device
+ * @cfg: the crypto configuration to check for
+ *
+ * Return: %true if @bdev supports hardware inline encryption with @cfg.
+ */
bool blk_crypto_config_supported_natively(struct block_device *bdev,
const struct blk_crypto_config *cfg)
{
- return __blk_crypto_cfg_supported(bdev_get_queue(bdev)->crypto_profile,
- cfg);
+ struct blk_crypto_profile *profile = bdev_get_queue(bdev)->crypto_profile;
+
+ if (!profile)
+ return false;
+ if (!(profile->modes_supported[cfg->crypto_mode] & cfg->data_unit_size))
+ return false;
+ if (profile->max_dun_bytes_supported < cfg->dun_bytes)
+ return false;
+ if (!(profile->key_types_supported & cfg->key_type))
+ return false;
+ return true;
}
/*
* Check if bios with @cfg can be en/decrypted by blk-crypto (i.e. either the
* block_device it's submitted to supports inline crypto, or the
--
2.54.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [f2fs-dev] [PATCH 02/16] blk-crypto: Fold __blk_crypto_cfg_supported() into its caller
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
0 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers via Linux-f2fs-devel @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: Ritesh Harjani, Theodore Ts'o, Zhang Yi, linux-f2fs-devel,
linux-block, Andreas Dilger, Ojaswin Mujoo, Baokun Li,
Jaegeuk Kim, linux-fsdevel, Jan Kara, linux-ext4,
Christoph Hellwig, Eric Biggers
__blk_crypto_cfg_supported() is called only by
blk_crypto_config_supported_natively(), so fold it in.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
block/blk-crypto-profile.c | 22 ----------------------
block/blk-crypto.c | 23 +++++++++++++++++++++--
2 files changed, 21 insertions(+), 24 deletions(-)
diff --git a/block/blk-crypto-profile.c b/block/blk-crypto-profile.c
index cf447ba4a66e..53126c091b0b 100644
--- a/block/blk-crypto-profile.c
+++ b/block/blk-crypto-profile.c
@@ -333,32 +333,10 @@ void blk_crypto_put_keyslot(struct blk_crypto_keyslot *slot)
spin_unlock_irqrestore(&profile->idle_slots_lock, flags);
wake_up(&profile->idle_slots_wait_queue);
}
}
-/**
- * __blk_crypto_cfg_supported() - Check whether the given crypto profile
- * supports the given crypto configuration.
- * @profile: the crypto profile to check
- * @cfg: the crypto configuration to check for
- *
- * Return: %true if @profile supports the given @cfg.
- */
-bool __blk_crypto_cfg_supported(struct blk_crypto_profile *profile,
- const struct blk_crypto_config *cfg)
-{
- if (!profile)
- return false;
- if (!(profile->modes_supported[cfg->crypto_mode] & cfg->data_unit_size))
- return false;
- if (profile->max_dun_bytes_supported < cfg->dun_bytes)
- return false;
- if (!(profile->key_types_supported & cfg->key_type))
- return false;
- return true;
-}
-
/*
* This is an internal function that evicts a key from an inline encryption
* device that can be either a real device or the blk-crypto-fallback "device".
* It is used only by blk_crypto_evict_key(); see that function for details.
*/
diff --git a/block/blk-crypto.c b/block/blk-crypto.c
index 15e25e41b166..dd83fc5af282 100644
--- a/block/blk-crypto.c
+++ b/block/blk-crypto.c
@@ -349,15 +349,34 @@ int blk_crypto_init_key(struct blk_crypto_key *blk_key,
return 0;
}
EXPORT_SYMBOL_GPL(blk_crypto_init_key);
+
+/**
+ * blk_crypto_config_supported_natively() - Check whether a block device
+ * supports hardware inline encryption
+ * with the given configuration.
+ * @bdev: the block device
+ * @cfg: the crypto configuration to check for
+ *
+ * Return: %true if @bdev supports hardware inline encryption with @cfg.
+ */
bool blk_crypto_config_supported_natively(struct block_device *bdev,
const struct blk_crypto_config *cfg)
{
- return __blk_crypto_cfg_supported(bdev_get_queue(bdev)->crypto_profile,
- cfg);
+ struct blk_crypto_profile *profile = bdev_get_queue(bdev)->crypto_profile;
+
+ if (!profile)
+ return false;
+ if (!(profile->modes_supported[cfg->crypto_mode] & cfg->data_unit_size))
+ return false;
+ if (profile->max_dun_bytes_supported < cfg->dun_bytes)
+ return false;
+ if (!(profile->key_types_supported & cfg->key_type))
+ return false;
+ return true;
}
/*
* Check if bios with @cfg can be en/decrypted by blk-crypto (i.e. either the
* block_device it's submitted to supports inline crypto, or the
--
2.54.0
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 03/16] blk-crypto: Allow control over whether hardware is used
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
-1 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: linux-fsdevel, linux-ext4, linux-f2fs-devel, linux-block,
Christoph Hellwig, Theodore Ts'o, Andreas Dilger, Baokun Li,
Jan Kara, Ojaswin Mujoo, Ritesh Harjani, Zhang Yi, Jaegeuk Kim,
Chao Yu, Eric Biggers
fscrypt uses inline encryption hardware only when the "inlinecrypt"
mount option is given. I'd like to keep that behavior even after
standardizing on the blk-crypto API for file contents encryption. That
is, the default should continue to be the well-tested CPU-based
encryption code, and the use of inline encryption hardware should
continue to be an opt-in feature for systems where it's beneficial and
has been fully validated (including verifying ciphertext correctness).
To support this use case, add an allow_hw field to struct
blk_crypto_config.
For now it's always set to true. Later commits will change that.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
block/blk-crypto.c | 8 +++++++-
drivers/md/dm-inlinecrypt.c | 2 +-
fs/crypto/inline_crypt.c | 3 ++-
include/linux/blk-crypto.h | 6 +++++-
4 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/block/blk-crypto.c b/block/blk-crypto.c
index dd83fc5af282..c157db869183 100644
--- a/block/blk-crypto.c
+++ b/block/blk-crypto.c
@@ -298,20 +298,21 @@ int __blk_crypto_rq_bio_prep(struct request *rq, struct bio *bio,
* @key_type: type of the key -- either raw or hardware-wrapped
* @crypto_mode: identifier for the encryption algorithm to use
* @dun_bytes: number of bytes that will be used to specify the DUN when this
* key is used
* @data_unit_size: the data unit size to use for en/decryption
+ * @allow_hw: true if using inline encryption hardware is allowed
*
* Return: 0 on success, -errno on failure. The caller is responsible for
* zeroizing both blk_key and key_bytes when done with them.
*/
int blk_crypto_init_key(struct blk_crypto_key *blk_key,
const u8 *key_bytes, size_t key_size,
enum blk_crypto_key_type key_type,
enum blk_crypto_mode_num crypto_mode,
unsigned int dun_bytes,
- unsigned int data_unit_size)
+ unsigned int data_unit_size, bool allow_hw)
{
const struct blk_crypto_mode *mode;
memset(blk_key, 0, sizeof(*blk_key));
@@ -326,10 +327,12 @@ int blk_crypto_init_key(struct blk_crypto_key *blk_key,
break;
case BLK_CRYPTO_KEY_TYPE_HW_WRAPPED:
if (key_size < mode->security_strength ||
key_size > BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE)
return -EINVAL;
+ if (!allow_hw)
+ return -EINVAL;
break;
default:
return -EINVAL;
}
@@ -341,10 +344,11 @@ int blk_crypto_init_key(struct blk_crypto_key *blk_key,
blk_key->crypto_cfg.crypto_mode = crypto_mode;
blk_key->crypto_cfg.dun_bytes = dun_bytes;
blk_key->crypto_cfg.data_unit_size = data_unit_size;
blk_key->crypto_cfg.key_type = key_type;
+ blk_key->crypto_cfg.allow_hw = allow_hw;
blk_key->data_unit_size_bits = ilog2(data_unit_size);
blk_key->size = key_size;
memcpy(blk_key->bytes, key_bytes, key_size);
return 0;
@@ -366,10 +370,12 @@ bool blk_crypto_config_supported_natively(struct block_device *bdev,
{
struct blk_crypto_profile *profile = bdev_get_queue(bdev)->crypto_profile;
if (!profile)
return false;
+ if (!cfg->allow_hw)
+ return false;
if (!(profile->modes_supported[cfg->crypto_mode] & cfg->data_unit_size))
return false;
if (profile->max_dun_bytes_supported < cfg->dun_bytes)
return false;
if (!(profile->key_types_supported & cfg->key_type))
diff --git a/drivers/md/dm-inlinecrypt.c b/drivers/md/dm-inlinecrypt.c
index be1b4aa8f28b..a0f039c1e153 100644
--- a/drivers/md/dm-inlinecrypt.c
+++ b/drivers/md/dm-inlinecrypt.c
@@ -404,11 +404,11 @@ static int inlinecrypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
(ctx->sector_bits - SECTOR_SHIFT);
dun_bytes = DIV_ROUND_UP(fls64(ctx->max_dun), 8);
err = blk_crypto_init_key(&ctx->key, key_bytes, ctx->key_size,
ctx->key_type, cipher->mode_num,
- dun_bytes, ctx->sector_size);
+ dun_bytes, ctx->sector_size, true);
if (err) {
ti->error = "Error initializing blk-crypto key";
goto bad;
}
diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c
index 47324062fee5..0d4c0dd04d20 100644
--- a/fs/crypto/inline_crypt.c
+++ b/fs/crypto/inline_crypt.c
@@ -132,10 +132,11 @@ int fscrypt_select_encryption_impl(struct fscrypt_inode_info *ci,
crypto_cfg.crypto_mode = ci->ci_mode->blk_crypto_mode;
crypto_cfg.data_unit_size = 1U << ci->ci_data_unit_bits;
crypto_cfg.dun_bytes = fscrypt_get_dun_bytes(ci);
crypto_cfg.key_type = is_hw_wrapped_key ?
BLK_CRYPTO_KEY_TYPE_HW_WRAPPED : BLK_CRYPTO_KEY_TYPE_RAW;
+ crypto_cfg.allow_hw = true;
devs = fscrypt_get_devices(sb, &num_devs);
if (IS_ERR(devs))
return PTR_ERR(devs);
@@ -173,11 +174,11 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
if (!blk_key)
return -ENOMEM;
err = blk_crypto_init_key(blk_key, key_bytes, key_size, key_type,
crypto_mode, fscrypt_get_dun_bytes(ci),
- 1U << ci->ci_data_unit_bits);
+ 1U << ci->ci_data_unit_bits, true);
if (err) {
fscrypt_err(inode, "error %d initializing blk-crypto key", err);
goto fail;
}
diff --git a/include/linux/blk-crypto.h b/include/linux/blk-crypto.h
index f7c3cb4a342f..7b9dca89aec9 100644
--- a/include/linux/blk-crypto.h
+++ b/include/linux/blk-crypto.h
@@ -75,16 +75,20 @@ enum blk_crypto_key_type {
* key. This is the size in bytes of each individual plaintext and
* ciphertext. This is always a power of 2. It might be e.g. the
* filesystem block size or the disk sector size.
* @dun_bytes: the maximum number of bytes of DUN used when using this key
* @key_type: the type of this key -- either raw or hardware-wrapped
+ * @allow_hw: true if inline encryption hardware will be used if available;
+ * false to always use CPU-based encryption (requires
+ * CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK)
*/
struct blk_crypto_config {
enum blk_crypto_mode_num crypto_mode;
unsigned int data_unit_size;
unsigned int dun_bytes;
enum blk_crypto_key_type key_type;
+ bool allow_hw;
};
/**
* struct blk_crypto_key - an inline encryption key
* @crypto_cfg: the crypto mode, data unit size, key type, and other
@@ -148,11 +152,11 @@ bool bio_crypt_dun_is_contiguous(const struct bio_crypt_ctx *bc,
int blk_crypto_init_key(struct blk_crypto_key *blk_key,
const u8 *key_bytes, size_t key_size,
enum blk_crypto_key_type key_type,
enum blk_crypto_mode_num crypto_mode,
unsigned int dun_bytes,
- unsigned int data_unit_size);
+ unsigned int data_unit_size, bool allow_hw);
int blk_crypto_start_using_key(struct block_device *bdev,
const struct blk_crypto_key *key);
void blk_crypto_evict_key(struct block_device *bdev,
--
2.54.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [f2fs-dev] [PATCH 03/16] blk-crypto: Allow control over whether hardware is used
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
0 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers via Linux-f2fs-devel @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: Ritesh Harjani, Theodore Ts'o, Zhang Yi, linux-f2fs-devel,
linux-block, Andreas Dilger, Ojaswin Mujoo, Baokun Li,
Jaegeuk Kim, linux-fsdevel, Jan Kara, linux-ext4,
Christoph Hellwig, Eric Biggers
fscrypt uses inline encryption hardware only when the "inlinecrypt"
mount option is given. I'd like to keep that behavior even after
standardizing on the blk-crypto API for file contents encryption. That
is, the default should continue to be the well-tested CPU-based
encryption code, and the use of inline encryption hardware should
continue to be an opt-in feature for systems where it's beneficial and
has been fully validated (including verifying ciphertext correctness).
To support this use case, add an allow_hw field to struct
blk_crypto_config.
For now it's always set to true. Later commits will change that.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
block/blk-crypto.c | 8 +++++++-
drivers/md/dm-inlinecrypt.c | 2 +-
fs/crypto/inline_crypt.c | 3 ++-
include/linux/blk-crypto.h | 6 +++++-
4 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/block/blk-crypto.c b/block/blk-crypto.c
index dd83fc5af282..c157db869183 100644
--- a/block/blk-crypto.c
+++ b/block/blk-crypto.c
@@ -298,20 +298,21 @@ int __blk_crypto_rq_bio_prep(struct request *rq, struct bio *bio,
* @key_type: type of the key -- either raw or hardware-wrapped
* @crypto_mode: identifier for the encryption algorithm to use
* @dun_bytes: number of bytes that will be used to specify the DUN when this
* key is used
* @data_unit_size: the data unit size to use for en/decryption
+ * @allow_hw: true if using inline encryption hardware is allowed
*
* Return: 0 on success, -errno on failure. The caller is responsible for
* zeroizing both blk_key and key_bytes when done with them.
*/
int blk_crypto_init_key(struct blk_crypto_key *blk_key,
const u8 *key_bytes, size_t key_size,
enum blk_crypto_key_type key_type,
enum blk_crypto_mode_num crypto_mode,
unsigned int dun_bytes,
- unsigned int data_unit_size)
+ unsigned int data_unit_size, bool allow_hw)
{
const struct blk_crypto_mode *mode;
memset(blk_key, 0, sizeof(*blk_key));
@@ -326,10 +327,12 @@ int blk_crypto_init_key(struct blk_crypto_key *blk_key,
break;
case BLK_CRYPTO_KEY_TYPE_HW_WRAPPED:
if (key_size < mode->security_strength ||
key_size > BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE)
return -EINVAL;
+ if (!allow_hw)
+ return -EINVAL;
break;
default:
return -EINVAL;
}
@@ -341,10 +344,11 @@ int blk_crypto_init_key(struct blk_crypto_key *blk_key,
blk_key->crypto_cfg.crypto_mode = crypto_mode;
blk_key->crypto_cfg.dun_bytes = dun_bytes;
blk_key->crypto_cfg.data_unit_size = data_unit_size;
blk_key->crypto_cfg.key_type = key_type;
+ blk_key->crypto_cfg.allow_hw = allow_hw;
blk_key->data_unit_size_bits = ilog2(data_unit_size);
blk_key->size = key_size;
memcpy(blk_key->bytes, key_bytes, key_size);
return 0;
@@ -366,10 +370,12 @@ bool blk_crypto_config_supported_natively(struct block_device *bdev,
{
struct blk_crypto_profile *profile = bdev_get_queue(bdev)->crypto_profile;
if (!profile)
return false;
+ if (!cfg->allow_hw)
+ return false;
if (!(profile->modes_supported[cfg->crypto_mode] & cfg->data_unit_size))
return false;
if (profile->max_dun_bytes_supported < cfg->dun_bytes)
return false;
if (!(profile->key_types_supported & cfg->key_type))
diff --git a/drivers/md/dm-inlinecrypt.c b/drivers/md/dm-inlinecrypt.c
index be1b4aa8f28b..a0f039c1e153 100644
--- a/drivers/md/dm-inlinecrypt.c
+++ b/drivers/md/dm-inlinecrypt.c
@@ -404,11 +404,11 @@ static int inlinecrypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
(ctx->sector_bits - SECTOR_SHIFT);
dun_bytes = DIV_ROUND_UP(fls64(ctx->max_dun), 8);
err = blk_crypto_init_key(&ctx->key, key_bytes, ctx->key_size,
ctx->key_type, cipher->mode_num,
- dun_bytes, ctx->sector_size);
+ dun_bytes, ctx->sector_size, true);
if (err) {
ti->error = "Error initializing blk-crypto key";
goto bad;
}
diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c
index 47324062fee5..0d4c0dd04d20 100644
--- a/fs/crypto/inline_crypt.c
+++ b/fs/crypto/inline_crypt.c
@@ -132,10 +132,11 @@ int fscrypt_select_encryption_impl(struct fscrypt_inode_info *ci,
crypto_cfg.crypto_mode = ci->ci_mode->blk_crypto_mode;
crypto_cfg.data_unit_size = 1U << ci->ci_data_unit_bits;
crypto_cfg.dun_bytes = fscrypt_get_dun_bytes(ci);
crypto_cfg.key_type = is_hw_wrapped_key ?
BLK_CRYPTO_KEY_TYPE_HW_WRAPPED : BLK_CRYPTO_KEY_TYPE_RAW;
+ crypto_cfg.allow_hw = true;
devs = fscrypt_get_devices(sb, &num_devs);
if (IS_ERR(devs))
return PTR_ERR(devs);
@@ -173,11 +174,11 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
if (!blk_key)
return -ENOMEM;
err = blk_crypto_init_key(blk_key, key_bytes, key_size, key_type,
crypto_mode, fscrypt_get_dun_bytes(ci),
- 1U << ci->ci_data_unit_bits);
+ 1U << ci->ci_data_unit_bits, true);
if (err) {
fscrypt_err(inode, "error %d initializing blk-crypto key", err);
goto fail;
}
diff --git a/include/linux/blk-crypto.h b/include/linux/blk-crypto.h
index f7c3cb4a342f..7b9dca89aec9 100644
--- a/include/linux/blk-crypto.h
+++ b/include/linux/blk-crypto.h
@@ -75,16 +75,20 @@ enum blk_crypto_key_type {
* key. This is the size in bytes of each individual plaintext and
* ciphertext. This is always a power of 2. It might be e.g. the
* filesystem block size or the disk sector size.
* @dun_bytes: the maximum number of bytes of DUN used when using this key
* @key_type: the type of this key -- either raw or hardware-wrapped
+ * @allow_hw: true if inline encryption hardware will be used if available;
+ * false to always use CPU-based encryption (requires
+ * CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK)
*/
struct blk_crypto_config {
enum blk_crypto_mode_num crypto_mode;
unsigned int data_unit_size;
unsigned int dun_bytes;
enum blk_crypto_key_type key_type;
+ bool allow_hw;
};
/**
* struct blk_crypto_key - an inline encryption key
* @crypto_cfg: the crypto mode, data unit size, key type, and other
@@ -148,11 +152,11 @@ bool bio_crypt_dun_is_contiguous(const struct bio_crypt_ctx *bc,
int blk_crypto_init_key(struct blk_crypto_key *blk_key,
const u8 *key_bytes, size_t key_size,
enum blk_crypto_key_type key_type,
enum blk_crypto_mode_num crypto_mode,
unsigned int dun_bytes,
- unsigned int data_unit_size);
+ unsigned int data_unit_size, bool allow_hw);
int blk_crypto_start_using_key(struct block_device *bdev,
const struct blk_crypto_key *key);
void blk_crypto_evict_key(struct block_device *bdev,
--
2.54.0
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 04/16] fscrypt: Fully disallow IV_INO_LBLK_32 with s_blocksize != PAGE_SIZE
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
-1 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: linux-fsdevel, linux-ext4, linux-f2fs-devel, linux-block,
Christoph Hellwig, Theodore Ts'o, Andreas Dilger, Baokun Li,
Jan Kara, Ojaswin Mujoo, Ritesh Harjani, Zhang Yi, Jaegeuk Kim,
Chao Yu, Eric Biggers
FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32 with s_blocksize != PAGE_SIZE works
only with the fs-layer implementation of file contents encryption, not
blk-crypto. This is a problem for standardizing on blk-crypto.
Fortunately, no one should be using this combination anyway. It doesn't
make sense because the entire point of IV_INO_LBLK_32 is to support
inline encryption hardware that is limited to 32-bit DUNs.
Thus, fully disallow IV_INO_LBLK_32 with s_blocksize != PAGE_SIZE.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
Documentation/filesystems/fscrypt.rst | 3 +++
fs/crypto/inline_crypt.c | 13 -------------
fs/crypto/policy.c | 17 +++++++++++++++++
3 files changed, 20 insertions(+), 13 deletions(-)
diff --git a/Documentation/filesystems/fscrypt.rst b/Documentation/filesystems/fscrypt.rst
index c0dd35f1af12..92b8f311e211 100644
--- a/Documentation/filesystems/fscrypt.rst
+++ b/Documentation/filesystems/fscrypt.rst
@@ -334,10 +334,13 @@ This format is optimized for use with inline encryption hardware
compliant with the eMMC v5.2 standard, which supports only 32 IV bits
per I/O request and may have only a small number of keyslots. This
format results in some level of IV reuse, so it should only be used
when necessary due to hardware limitations.
+IV_INO_LBLK_32 is supported only when the filesystem block size is
+equal to the page size.
+
Key identifiers
---------------
For master keys used for v2 encryption policies, a unique 16-byte "key
identifier" is also derived using the KDF. This value is stored in
diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c
index 0d4c0dd04d20..4f045ad1dca8 100644
--- a/fs/crypto/inline_crypt.c
+++ b/fs/crypto/inline_crypt.c
@@ -110,23 +110,10 @@ int fscrypt_select_encryption_impl(struct fscrypt_inode_info *ci,
/* The filesystem must be mounted with -o inlinecrypt */
if (!(sb->s_flags & SB_INLINECRYPT))
return 0;
- /*
- * When a page contains multiple logically contiguous filesystem blocks,
- * some filesystem code only calls fscrypt_mergeable_bio() for the first
- * block in the page. This is fine for most of fscrypt's IV generation
- * strategies, where contiguous blocks imply contiguous IVs. But it
- * doesn't work with IV_INO_LBLK_32. For now, simply exclude
- * IV_INO_LBLK_32 with blocksize != PAGE_SIZE from inline encryption.
- */
- if ((fscrypt_policy_flags(&ci->ci_policy) &
- FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) &&
- sb->s_blocksize != PAGE_SIZE)
- return 0;
-
/*
* On all the filesystem's block devices, blk-crypto must support the
* crypto configuration that the file would use.
*/
crypto_cfg.crypto_mode = ci->ci_mode->blk_crypto_mode;
diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c
index f40fb5924e75..a7322dba7557 100644
--- a/fs/crypto/policy.c
+++ b/fs/crypto/policy.c
@@ -175,10 +175,27 @@ static bool supported_iv_ino_lblk_policy(const struct fscrypt_policy_v2 *policy,
fscrypt_warn(inode,
"Can't use %s policy on filesystem '%s' because its maximum file size is too large",
type, sb->s_id);
return false;
}
+
+ /*
+ * IV_INO_LBLK_32 isn't compatible with inline encryption when
+ * s_blocksize != PAGE_SIZE. In that case the DUN can wrap around in
+ * the middle of a page, but sometimes fscrypt_mergeable_bio() is called
+ * only for the first block per page. Since IV_INO_LBLK_32 exists only
+ * to support inline encryption hardware that is limited to 32-bit DUNs,
+ * just disallow IV_INO_LBLK_32 with s_blocksize != PAGE_SIZE entirely.
+ */
+ if ((policy->flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) &&
+ sb->s_blocksize != PAGE_SIZE) {
+ fscrypt_warn(inode,
+ "Can't use %s policy on filesystem '%s' with block size != PAGE_SIZE",
+ type, sb->s_id);
+ return false;
+ }
+
return true;
}
static bool fscrypt_supported_v1_policy(const struct fscrypt_policy_v1 *policy,
const struct inode *inode)
--
2.54.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [f2fs-dev] [PATCH 04/16] fscrypt: Fully disallow IV_INO_LBLK_32 with s_blocksize != PAGE_SIZE
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
0 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers via Linux-f2fs-devel @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: Ritesh Harjani, Theodore Ts'o, Zhang Yi, linux-f2fs-devel,
linux-block, Andreas Dilger, Ojaswin Mujoo, Baokun Li,
Jaegeuk Kim, linux-fsdevel, Jan Kara, linux-ext4,
Christoph Hellwig, Eric Biggers
FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32 with s_blocksize != PAGE_SIZE works
only with the fs-layer implementation of file contents encryption, not
blk-crypto. This is a problem for standardizing on blk-crypto.
Fortunately, no one should be using this combination anyway. It doesn't
make sense because the entire point of IV_INO_LBLK_32 is to support
inline encryption hardware that is limited to 32-bit DUNs.
Thus, fully disallow IV_INO_LBLK_32 with s_blocksize != PAGE_SIZE.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
Documentation/filesystems/fscrypt.rst | 3 +++
fs/crypto/inline_crypt.c | 13 -------------
fs/crypto/policy.c | 17 +++++++++++++++++
3 files changed, 20 insertions(+), 13 deletions(-)
diff --git a/Documentation/filesystems/fscrypt.rst b/Documentation/filesystems/fscrypt.rst
index c0dd35f1af12..92b8f311e211 100644
--- a/Documentation/filesystems/fscrypt.rst
+++ b/Documentation/filesystems/fscrypt.rst
@@ -334,10 +334,13 @@ This format is optimized for use with inline encryption hardware
compliant with the eMMC v5.2 standard, which supports only 32 IV bits
per I/O request and may have only a small number of keyslots. This
format results in some level of IV reuse, so it should only be used
when necessary due to hardware limitations.
+IV_INO_LBLK_32 is supported only when the filesystem block size is
+equal to the page size.
+
Key identifiers
---------------
For master keys used for v2 encryption policies, a unique 16-byte "key
identifier" is also derived using the KDF. This value is stored in
diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c
index 0d4c0dd04d20..4f045ad1dca8 100644
--- a/fs/crypto/inline_crypt.c
+++ b/fs/crypto/inline_crypt.c
@@ -110,23 +110,10 @@ int fscrypt_select_encryption_impl(struct fscrypt_inode_info *ci,
/* The filesystem must be mounted with -o inlinecrypt */
if (!(sb->s_flags & SB_INLINECRYPT))
return 0;
- /*
- * When a page contains multiple logically contiguous filesystem blocks,
- * some filesystem code only calls fscrypt_mergeable_bio() for the first
- * block in the page. This is fine for most of fscrypt's IV generation
- * strategies, where contiguous blocks imply contiguous IVs. But it
- * doesn't work with IV_INO_LBLK_32. For now, simply exclude
- * IV_INO_LBLK_32 with blocksize != PAGE_SIZE from inline encryption.
- */
- if ((fscrypt_policy_flags(&ci->ci_policy) &
- FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) &&
- sb->s_blocksize != PAGE_SIZE)
- return 0;
-
/*
* On all the filesystem's block devices, blk-crypto must support the
* crypto configuration that the file would use.
*/
crypto_cfg.crypto_mode = ci->ci_mode->blk_crypto_mode;
diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c
index f40fb5924e75..a7322dba7557 100644
--- a/fs/crypto/policy.c
+++ b/fs/crypto/policy.c
@@ -175,10 +175,27 @@ static bool supported_iv_ino_lblk_policy(const struct fscrypt_policy_v2 *policy,
fscrypt_warn(inode,
"Can't use %s policy on filesystem '%s' because its maximum file size is too large",
type, sb->s_id);
return false;
}
+
+ /*
+ * IV_INO_LBLK_32 isn't compatible with inline encryption when
+ * s_blocksize != PAGE_SIZE. In that case the DUN can wrap around in
+ * the middle of a page, but sometimes fscrypt_mergeable_bio() is called
+ * only for the first block per page. Since IV_INO_LBLK_32 exists only
+ * to support inline encryption hardware that is limited to 32-bit DUNs,
+ * just disallow IV_INO_LBLK_32 with s_blocksize != PAGE_SIZE entirely.
+ */
+ if ((policy->flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) &&
+ sb->s_blocksize != PAGE_SIZE) {
+ fscrypt_warn(inode,
+ "Can't use %s policy on filesystem '%s' with block size != PAGE_SIZE",
+ type, sb->s_id);
+ return false;
+ }
+
return true;
}
static bool fscrypt_supported_v1_policy(const struct fscrypt_policy_v1 *policy,
const struct inode *inode)
--
2.54.0
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 05/16] fscrypt: Always use blk-crypto for contents on block-based filesystems
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
-1 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: linux-fsdevel, linux-ext4, linux-f2fs-devel, linux-block,
Christoph Hellwig, Theodore Ts'o, Andreas Dilger, Baokun Li,
Jan Kara, Ojaswin Mujoo, Ritesh Harjani, Zhang Yi, Jaegeuk Kim,
Chao Yu, Eric Biggers
For encrypting and decrypting file contents on block-based filesystems
(i.e., ext4 and f2fs, but not ceph and ubifs), always use blk-crypto
instead of fs-layer crypto (direct use of crypto_skcipher).
Since the blk-crypto API provides a fallback to CPU-based encryption,
it's all that's needed on block-based filesystems. The support for two
alternative block-based file contents encryption implementations,
fs-layer and blk-crypto, existed mainly for historical reasons, as the
fs-layer path came first. Some of it is also still needed for the
non-block-based filesystems, but a lot of it isn't.
Removing the duplicate fs-layer code paths greatly simplifies the code,
most of which is done in later commits.
Specific implementation details:
- SB_INLINECRYPT now controls whether blk_crypto_config::allow_hw is set
to true, instead of whether blk-crypto is used at all. The effect is
that the semantics are preserved: the inlinecrypt mount option selects
the use of inline encryption hardware instead of the CPU.
- Set up a blk_crypto_key iff the file is a regular file on a
block-based filesystem. To determine whether the filesystem is
block-based, add a bit fscrypt_operations::is_block_based.
- Remove fscrypt_select_encryption_impl(). Move the logging logic that
was previously there into fscrypt_prepare_inline_crypt_key(). Note
that blk_crypto_config_supported() is no longer needed.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
Documentation/filesystems/fscrypt.rst | 36 +++----
arch/loongarch/configs/loongson32_defconfig | 1 -
arch/loongarch/configs/loongson64_defconfig | 1 -
fs/crypto/Kconfig | 8 +-
fs/crypto/fscrypt_private.h | 21 +---
fs/crypto/inline_crypt.c | 110 ++++++--------------
fs/crypto/keysetup.c | 31 +-----
fs/ext4/crypto.c | 1 +
fs/f2fs/super.c | 1 +
include/linux/fscrypt.h | 28 ++---
10 files changed, 69 insertions(+), 169 deletions(-)
diff --git a/Documentation/filesystems/fscrypt.rst b/Documentation/filesystems/fscrypt.rst
index 92b8f311e211..370a5ef73ef2 100644
--- a/Documentation/filesystems/fscrypt.rst
+++ b/Documentation/filesystems/fscrypt.rst
@@ -1316,36 +1316,24 @@ this by validating all top-level encryption policies prior to access.
Inline encryption support
=========================
Many newer systems (especially mobile SoCs) have *inline encryption
hardware* that can encrypt/decrypt data while it is on its way to/from
-the storage device. Linux supports inline encryption through a set of
-extensions to the block layer called *blk-crypto*. blk-crypto allows
-filesystems to attach encryption contexts to bios (I/O requests) to
-specify how the data will be encrypted or decrypted in-line. For more
-information about blk-crypto, see
-:ref:`Documentation/block/inline-encryption.rst <inline_encryption>`.
+the storage device.
On supported filesystems (currently ext4 and f2fs), fscrypt can use
-blk-crypto instead of the kernel crypto API to encrypt/decrypt file
-contents. To enable this, set CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y in
-the kernel configuration, and specify the "inlinecrypt" mount option
-when mounting the filesystem.
-
-Note that the "inlinecrypt" mount option just specifies to use inline
-encryption when possible; it doesn't force its use. fscrypt will
-still fall back to using the kernel crypto API on files where the
-inline encryption hardware doesn't have the needed crypto capabilities
-(e.g. support for the needed encryption algorithm and data unit size)
-and where blk-crypto-fallback is unusable. (For blk-crypto-fallback
-to be usable, it must be enabled in the kernel configuration with
-CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y, and the file must be
-protected by a raw key rather than a hardware-wrapped key.)
-
-Currently fscrypt always uses the filesystem block size (which is
-usually 4096 bytes) as the data unit size. Therefore, it can only use
-inline encryption hardware that supports that data unit size.
+inline encryption hardware instead of the CPU to encrypt/decrypt file
+contents. To enable this, specify the "inlinecrypt" mount option when
+mounting the filesystem.
+
+This causes the filesystem to use inline encryption hardware whenever
+possible, falling back to the CPU only if such hardware is absent or
+doesn't provide the needed crypto capabilities.
+
+For more information about the kernel's support for inline encryption
+hardware, see :ref:`Documentation/block/inline-encryption.rst
+<inline_encryption>`.
Inline encryption doesn't affect the ciphertext or other aspects of
the on-disk format, so users may freely switch back and forth between
using "inlinecrypt" and not using "inlinecrypt". An exception is that
files that are protected by a hardware-wrapped key can only be
diff --git a/arch/loongarch/configs/loongson32_defconfig b/arch/loongarch/configs/loongson32_defconfig
index 7c8f01513ed2..6bf2867dbdc6 100644
--- a/arch/loongarch/configs/loongson32_defconfig
+++ b/arch/loongarch/configs/loongson32_defconfig
@@ -967,11 +967,10 @@ CONFIG_BTRFS_FS_POSIX_ACL=y
CONFIG_F2FS_FS=m
CONFIG_F2FS_FS_SECURITY=y
CONFIG_F2FS_CHECK_FS=y
CONFIG_F2FS_FS_COMPRESSION=y
CONFIG_FS_ENCRYPTION=y
-CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y
CONFIG_FS_VERITY=y
CONFIG_FANOTIFY=y
CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y
CONFIG_QUOTA=y
# CONFIG_PRINT_QUOTA_WARNING is not set
diff --git a/arch/loongarch/configs/loongson64_defconfig b/arch/loongarch/configs/loongson64_defconfig
index 8e3906d3bd70..def104c9d405 100644
--- a/arch/loongarch/configs/loongson64_defconfig
+++ b/arch/loongarch/configs/loongson64_defconfig
@@ -998,11 +998,10 @@ CONFIG_BTRFS_FS_POSIX_ACL=y
CONFIG_F2FS_FS=m
CONFIG_F2FS_FS_SECURITY=y
CONFIG_F2FS_CHECK_FS=y
CONFIG_F2FS_FS_COMPRESSION=y
CONFIG_FS_ENCRYPTION=y
-CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y
CONFIG_FS_VERITY=y
CONFIG_FANOTIFY=y
CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y
CONFIG_QUOTA=y
# CONFIG_PRINT_QUOTA_WARNING is not set
diff --git a/fs/crypto/Kconfig b/fs/crypto/Kconfig
index 983d8ad1f417..cd934e31dec4 100644
--- a/fs/crypto/Kconfig
+++ b/fs/crypto/Kconfig
@@ -1,8 +1,10 @@
# SPDX-License-Identifier: GPL-2.0-only
config FS_ENCRYPTION
bool "FS Encryption (Per-file encryption)"
+ select BLK_INLINE_ENCRYPTION if BLOCK
+ select BLK_INLINE_ENCRYPTION_FALLBACK if BLOCK
select CRYPTO
select CRYPTO_SKCIPHER
select CRYPTO_LIB_AES
select CRYPTO_LIB_SHA256
select CRYPTO_LIB_SHA512
@@ -32,9 +34,7 @@ config FS_ENCRYPTION_ALGS
select CRYPTO_CBC
select CRYPTO_CTS
select CRYPTO_XTS
config FS_ENCRYPTION_INLINE_CRYPT
- bool "Enable fscrypt to use inline crypto"
- depends on FS_ENCRYPTION && BLK_INLINE_ENCRYPTION
- help
- Enable fscrypt to use inline encryption hardware if available.
+ bool
+ default y if FS_ENCRYPTION && BLOCK
diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h
index 8234ee542476..57b7ae2cfafc 100644
--- a/fs/crypto/fscrypt_private.h
+++ b/fs/crypto/fscrypt_private.h
@@ -264,18 +264,10 @@ struct fscrypt_inode_info {
struct fscrypt_prepared_key ci_enc_key;
/* True if ci_enc_key should be freed when this struct is freed */
u8 ci_owns_key : 1;
-#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT
- /*
- * True if this inode will use inline encryption (blk-crypto) instead of
- * the traditional filesystem-layer encryption.
- */
- u8 ci_inlinecrypt : 1;
-#endif
-
/* True if ci_dirhash_key is initialized */
u8 ci_dirhash_key_initialized : 1;
/*
* log2 of the data unit size (granularity of contents encryption) of
@@ -408,17 +400,16 @@ void fscrypt_hkdf_expand(const struct hmac_sha512_key *hkdf, u8 context,
const u8 *info, unsigned int infolen,
u8 *okm, unsigned int okmlen);
/* inline_crypt.c */
#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT
-int fscrypt_select_encryption_impl(struct fscrypt_inode_info *ci,
- bool is_hw_wrapped_key);
-
static inline bool
fscrypt_using_inline_encryption(const struct fscrypt_inode_info *ci)
{
- return ci->ci_inlinecrypt;
+ const struct inode *inode = ci->ci_inode;
+
+ return S_ISREG(inode->i_mode) && inode->i_sb->s_cop->is_block_based;
}
int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
const u8 *key_bytes, size_t key_size,
bool is_hw_wrapped,
@@ -444,16 +435,10 @@ fscrypt_is_key_prepared(const struct fscrypt_prepared_key *prep_key,
return prep_key->tfm != NULL;
}
#else /* CONFIG_FS_ENCRYPTION_INLINE_CRYPT */
-static inline int fscrypt_select_encryption_impl(struct fscrypt_inode_info *ci,
- bool is_hw_wrapped_key)
-{
- return 0;
-}
-
static inline bool
fscrypt_using_inline_encryption(const struct fscrypt_inode_info *ci)
{
return false;
}
diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c
index 4f045ad1dca8..caf706215621 100644
--- a/fs/crypto/inline_crypt.c
+++ b/fs/crypto/inline_crypt.c
@@ -68,106 +68,61 @@ static unsigned int fscrypt_get_dun_bytes(const struct fscrypt_inode_info *ci)
* filesystems or files are using each implementation. However, *usually*
* systems use just one implementation per mode, which makes these messages
* helpful for debugging problems where the "wrong" implementation is used.
*/
static void fscrypt_log_blk_crypto_impl(struct fscrypt_mode *mode,
- struct block_device **devs,
- unsigned int num_devs,
- const struct blk_crypto_config *cfg)
+ struct block_device *dev,
+ const struct blk_crypto_key *blk_key)
{
- unsigned int i;
-
- for (i = 0; i < num_devs; i++) {
- if (!IS_ENABLED(CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK) ||
- blk_crypto_config_supported_natively(devs[i], cfg)) {
- if (!xchg(&mode->logged_blk_crypto_native, 1))
- pr_info("fscrypt: %s using blk-crypto (native)\n",
- mode->friendly_name);
- } else if (!xchg(&mode->logged_blk_crypto_fallback, 1)) {
- pr_info("fscrypt: %s using blk-crypto-fallback\n",
+ if (blk_crypto_config_supported_natively(dev, &blk_key->crypto_cfg)) {
+ if (!xchg(&mode->logged_blk_crypto_native, 1))
+ pr_info("fscrypt: %s using blk-crypto (native)\n",
mode->friendly_name);
- }
+ } else if (!xchg(&mode->logged_blk_crypto_fallback, 1)) {
+ pr_info("fscrypt: %s using blk-crypto-fallback\n",
+ mode->friendly_name);
}
}
-/* Enable inline encryption for this file if supported. */
-int fscrypt_select_encryption_impl(struct fscrypt_inode_info *ci,
- bool is_hw_wrapped_key)
-{
- const struct inode *inode = ci->ci_inode;
- struct super_block *sb = inode->i_sb;
- struct blk_crypto_config crypto_cfg;
- struct block_device **devs;
- unsigned int num_devs;
- unsigned int i;
-
- /* The file must need contents encryption, not filenames encryption */
- if (!S_ISREG(inode->i_mode))
- return 0;
-
- /* The crypto mode must have a blk-crypto counterpart */
- if (ci->ci_mode->blk_crypto_mode == BLK_ENCRYPTION_MODE_INVALID)
- return 0;
-
- /* The filesystem must be mounted with -o inlinecrypt */
- if (!(sb->s_flags & SB_INLINECRYPT))
- return 0;
-
- /*
- * On all the filesystem's block devices, blk-crypto must support the
- * crypto configuration that the file would use.
- */
- crypto_cfg.crypto_mode = ci->ci_mode->blk_crypto_mode;
- crypto_cfg.data_unit_size = 1U << ci->ci_data_unit_bits;
- crypto_cfg.dun_bytes = fscrypt_get_dun_bytes(ci);
- crypto_cfg.key_type = is_hw_wrapped_key ?
- BLK_CRYPTO_KEY_TYPE_HW_WRAPPED : BLK_CRYPTO_KEY_TYPE_RAW;
- crypto_cfg.allow_hw = true;
-
- devs = fscrypt_get_devices(sb, &num_devs);
- if (IS_ERR(devs))
- return PTR_ERR(devs);
-
- for (i = 0; i < num_devs; i++) {
- if (!blk_crypto_config_supported(devs[i], &crypto_cfg))
- goto out_free_devs;
- }
-
- fscrypt_log_blk_crypto_impl(ci->ci_mode, devs, num_devs, &crypto_cfg);
-
- ci->ci_inlinecrypt = true;
-out_free_devs:
- kfree(devs);
-
- return 0;
-}
-
int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
const u8 *key_bytes, size_t key_size,
bool is_hw_wrapped,
const struct fscrypt_inode_info *ci)
{
const struct inode *inode = ci->ci_inode;
struct super_block *sb = inode->i_sb;
- enum blk_crypto_mode_num crypto_mode = ci->ci_mode->blk_crypto_mode;
+ bool inlinecrypt = sb->s_flags & SB_INLINECRYPT;
+ struct fscrypt_mode *mode = ci->ci_mode;
enum blk_crypto_key_type key_type = is_hw_wrapped ?
BLK_CRYPTO_KEY_TYPE_HW_WRAPPED : BLK_CRYPTO_KEY_TYPE_RAW;
struct blk_crypto_key *blk_key;
struct block_device **devs;
unsigned int num_devs;
unsigned int i;
int err;
+ if (is_hw_wrapped && !inlinecrypt) {
+ /*
+ * blk_crypto_init_key() would catch this anyway, but this
+ * provides a clearer error message.
+ */
+ fscrypt_err(
+ inode,
+ "Hardware-wrapped keys require inline encryption (-o inlinecrypt)");
+ return -EINVAL;
+ }
+
blk_key = kmalloc_obj(*blk_key);
if (!blk_key)
return -ENOMEM;
err = blk_crypto_init_key(blk_key, key_bytes, key_size, key_type,
- crypto_mode, fscrypt_get_dun_bytes(ci),
- 1U << ci->ci_data_unit_bits, true);
+ mode->blk_crypto_mode,
+ fscrypt_get_dun_bytes(ci),
+ 1U << ci->ci_data_unit_bits, inlinecrypt);
if (err) {
- fscrypt_err(inode, "error %d initializing blk-crypto key", err);
+ fscrypt_err(inode, "Error %d initializing blk-crypto key", err);
goto fail;
}
/* Start using blk-crypto on all the filesystem's block devices. */
devs = fscrypt_get_devices(sb, &num_devs);
@@ -177,14 +132,21 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
}
for (i = 0; i < num_devs; i++) {
err = blk_crypto_start_using_key(devs[i], blk_key);
if (err)
break;
+ fscrypt_log_blk_crypto_impl(mode, devs[i], blk_key);
}
kfree(devs);
if (err) {
- fscrypt_err(inode, "error %d starting to use blk-crypto", err);
+ if (err == -EOPNOTSUPP && is_hw_wrapped)
+ fscrypt_err(
+ inode,
+ "Hardware-wrapped key required, but no suitable inline encryption capabilities are available");
+ else
+ fscrypt_err(inode,
+ "Error %d starting to use blk-crypto", err);
goto fail;
}
prep_key->blk_key = blk_key;
return 0;
@@ -241,16 +203,10 @@ int fscrypt_derive_sw_secret(struct super_block *sb,
"%s: block device doesn't support hardware-wrapped keys\n",
sb->s_id);
return err;
}
-bool __fscrypt_inode_uses_inline_crypto(const struct inode *inode)
-{
- return fscrypt_get_inode_info_raw(inode)->ci_inlinecrypt;
-}
-EXPORT_SYMBOL_GPL(__fscrypt_inode_uses_inline_crypto);
-
static void fscrypt_generate_dun(const struct fscrypt_inode_info *ci,
loff_t pos, u64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE])
{
union fscrypt_iv iv;
int i;
diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c
index cfd348e2252e..c9041f245246 100644
--- a/fs/crypto/keysetup.c
+++ b/fs/crypto/keysetup.c
@@ -142,13 +142,13 @@ fscrypt_allocate_skcipher(struct fscrypt_mode *mode, const u8 *raw_key,
return ERR_PTR(err);
}
/*
* Prepare the crypto transform object or blk-crypto key in @prep_key, given the
- * raw key, encryption mode (@ci->ci_mode), flag indicating which encryption
- * implementation (fs-layer or blk-crypto) will be used (@ci->ci_inlinecrypt),
- * and IV generation method (@ci->ci_policy.flags).
+ * raw key, encryption mode (@ci->ci_mode), predicate indicating which style of
+ * key is needed (fscrypt_using_inline_encryption(ci)), IV generation method
+ * (@ci->ci_policy.flags), and data unit size (@ci->ci_data_unit_bits).
*/
int fscrypt_prepare_key(struct fscrypt_prepared_key *prep_key,
const u8 *raw_key, const struct fscrypt_inode_info *ci)
{
struct crypto_sync_skcipher *tfm;
@@ -222,27 +222,12 @@ static int setup_per_mode_enc_key(struct fscrypt_inode_info *ci,
struct fscrypt_prepared_key *prep_key;
struct fscrypt_mode_key *new_node;
u8 raw_mode_key[FSCRYPT_MAX_RAW_KEY_SIZE];
u8 hkdf_info[sizeof(mode_num) + sizeof(sb->s_uuid)];
unsigned int hkdf_infolen = 0;
- bool use_hw_wrapped_key = false;
int err;
- if (mk->mk_secret.is_hw_wrapped && S_ISREG(inode->i_mode)) {
- /* Using a hardware-wrapped key for file contents encryption */
- if (!fscrypt_using_inline_encryption(ci)) {
- if (sb->s_flags & SB_INLINECRYPT)
- fscrypt_warn(ci->ci_inode,
- "Hardware-wrapped key required, but no suitable inline encryption capabilities are available");
- else
- fscrypt_warn(ci->ci_inode,
- "Hardware-wrapped keys require inline encryption (-o inlinecrypt)");
- return -EINVAL;
- }
- use_hw_wrapped_key = true;
- }
-
prep_key = fscrypt_find_mode_key(mk, hkdf_context, mode_num, ci);
if (prep_key) {
ci->ci_enc_key = *prep_key;
return 0;
}
@@ -261,11 +246,11 @@ static int setup_per_mode_enc_key(struct fscrypt_inode_info *ci,
new_node->hkdf_context = hkdf_context;
new_node->mode_num = mode_num;
new_node->data_unit_bits = ci->ci_data_unit_bits;
prep_key = &new_node->key;
- if (use_hw_wrapped_key) {
+ if (mk->mk_secret.is_hw_wrapped && S_ISREG(inode->i_mode)) {
err = fscrypt_prepare_inline_crypt_key(prep_key,
mk->mk_secret.bytes,
mk->mk_secret.size, true,
ci);
} else {
@@ -507,14 +492,10 @@ static int setup_file_encryption_key(struct fscrypt_inode_info *ci,
}
if (unlikely(!mk)) {
if (ci->ci_policy.version != FSCRYPT_POLICY_V1)
return -ENOKEY;
- err = fscrypt_select_encryption_impl(ci, false);
- if (err)
- return err;
-
/*
* As a legacy fallback for v1 policies, search for the key in
* the current task's subscribed keyrings too. Don't move this
* to before the search of ->s_master_keys, since users
* shouldn't be able to override filesystem-level keys.
@@ -532,14 +513,10 @@ static int setup_file_encryption_key(struct fscrypt_inode_info *ci,
if (!fscrypt_valid_master_key_size(mk, ci)) {
err = -ENOKEY;
goto out_release_key;
}
- err = fscrypt_select_encryption_impl(ci, mk->mk_secret.is_hw_wrapped);
- if (err)
- goto out_release_key;
-
switch (ci->ci_policy.version) {
case FSCRYPT_POLICY_V1:
if (WARN_ON_ONCE(mk->mk_secret.is_hw_wrapped)) {
/*
* This should never happen, as adding a v1 policy key
diff --git a/fs/ext4/crypto.c b/fs/ext4/crypto.c
index f41f320f4437..6b809ac80ef7 100644
--- a/fs/ext4/crypto.c
+++ b/fs/ext4/crypto.c
@@ -234,10 +234,11 @@ static bool ext4_has_stable_inodes(struct super_block *sb)
}
const struct fscrypt_operations ext4_cryptops = {
.inode_info_offs = (int)offsetof(struct ext4_inode_info, i_crypt_info) -
(int)offsetof(struct ext4_inode_info, vfs_inode),
+ .is_block_based = 1,
.needs_bounce_pages = 1,
.has_32bit_inodes = 1,
.supports_subblock_data_units = 1,
.legacy_key_prefix = "ext4:",
.get_context = ext4_get_context,
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index ccf806b676f5..f3f6768f8cca 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -3752,10 +3752,11 @@ static struct block_device **f2fs_get_devices(struct super_block *sb,
}
static const struct fscrypt_operations f2fs_cryptops = {
.inode_info_offs = (int)offsetof(struct f2fs_inode_info, i_crypt_info) -
(int)offsetof(struct f2fs_inode_info, vfs_inode),
+ .is_block_based = 1,
.needs_bounce_pages = 1,
.has_32bit_inodes = 1,
.supports_subblock_data_units = 1,
.legacy_key_prefix = "f2fs:",
.get_context = f2fs_get_context,
diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h
index 54712ec61ffb..8d19b95150f1 100644
--- a/include/linux/fscrypt.h
+++ b/include/linux/fscrypt.h
@@ -67,18 +67,19 @@ struct fscrypt_operations {
* the common part of the inode (the 'struct inode').
*/
ptrdiff_t inode_info_offs;
/*
- * If set, then fs/crypto/ will allocate a global bounce page pool the
- * first time an encryption key is set up for a file. The bounce page
- * pool is required by the following functions:
- *
- * - fscrypt_encrypt_pagecache_blocks()
- * - fscrypt_zeroout_range() for files not using inline crypto
- *
- * If the filesystem doesn't use those, it doesn't need to set this.
+ * Set to 1 if the filesystem is block-based. This causes fs/crypto/ to
+ * set up the key for regular files as a blk_crypto_key. The filesystem
+ * then uses fscrypt_set_bio_crypt_ctx() and similar functions.
+ */
+ unsigned int is_block_based : 1;
+
+ /*
+ * Set to 1 if the filesystem uses fscrypt_encrypt_pagecache_blocks().
+ * This enables the allocation of the bounce page pool it requires.
*/
unsigned int needs_bounce_pages : 1;
/*
* If set, then fs/crypto/ will allow the use of encryption settings
@@ -861,12 +862,10 @@ static inline void fscrypt_set_ops(struct super_block *sb,
#endif /* !CONFIG_FS_ENCRYPTION */
/* inline_crypt.c */
#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT
-bool __fscrypt_inode_uses_inline_crypto(const struct inode *inode);
-
void fscrypt_set_bio_crypt_ctx(struct bio *bio, const struct inode *inode,
loff_t pos, gfp_t gfp_mask);
bool fscrypt_mergeable_bio(struct bio *bio, const struct inode *inode,
loff_t pos);
@@ -875,15 +874,10 @@ bool fscrypt_dio_supported(struct inode *inode);
u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk, u64 nr_blocks);
#else /* CONFIG_FS_ENCRYPTION_INLINE_CRYPT */
-static inline bool __fscrypt_inode_uses_inline_crypto(const struct inode *inode)
-{
- return false;
-}
-
static inline void fscrypt_set_bio_crypt_ctx(struct bio *bio,
const struct inode *inode,
loff_t pos, gfp_t gfp_mask) { }
static inline bool fscrypt_mergeable_bio(struct bio *bio,
@@ -915,11 +909,11 @@ static inline u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk,
* than in the filesystem layer.
*/
static inline bool fscrypt_inode_uses_inline_crypto(const struct inode *inode)
{
return fscrypt_needs_contents_encryption(inode) &&
- __fscrypt_inode_uses_inline_crypto(inode);
+ inode->i_sb->s_cop->is_block_based;
}
/**
* fscrypt_inode_uses_fs_layer_crypto() - test whether an inode uses fs-layer
* encryption
@@ -930,11 +924,11 @@ static inline bool fscrypt_inode_uses_inline_crypto(const struct inode *inode)
* block layer via blk-crypto.
*/
static inline bool fscrypt_inode_uses_fs_layer_crypto(const struct inode *inode)
{
return fscrypt_needs_contents_encryption(inode) &&
- !__fscrypt_inode_uses_inline_crypto(inode);
+ !inode->i_sb->s_cop->is_block_based;
}
/**
* fscrypt_has_encryption_key() - check whether an inode has had its key set up
* @inode: the inode to check
--
2.54.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [f2fs-dev] [PATCH 05/16] fscrypt: Always use blk-crypto for contents on block-based filesystems
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
0 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers via Linux-f2fs-devel @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: Ritesh Harjani, Theodore Ts'o, Zhang Yi, linux-f2fs-devel,
linux-block, Andreas Dilger, Ojaswin Mujoo, Baokun Li,
Jaegeuk Kim, linux-fsdevel, Jan Kara, linux-ext4,
Christoph Hellwig, Eric Biggers
For encrypting and decrypting file contents on block-based filesystems
(i.e., ext4 and f2fs, but not ceph and ubifs), always use blk-crypto
instead of fs-layer crypto (direct use of crypto_skcipher).
Since the blk-crypto API provides a fallback to CPU-based encryption,
it's all that's needed on block-based filesystems. The support for two
alternative block-based file contents encryption implementations,
fs-layer and blk-crypto, existed mainly for historical reasons, as the
fs-layer path came first. Some of it is also still needed for the
non-block-based filesystems, but a lot of it isn't.
Removing the duplicate fs-layer code paths greatly simplifies the code,
most of which is done in later commits.
Specific implementation details:
- SB_INLINECRYPT now controls whether blk_crypto_config::allow_hw is set
to true, instead of whether blk-crypto is used at all. The effect is
that the semantics are preserved: the inlinecrypt mount option selects
the use of inline encryption hardware instead of the CPU.
- Set up a blk_crypto_key iff the file is a regular file on a
block-based filesystem. To determine whether the filesystem is
block-based, add a bit fscrypt_operations::is_block_based.
- Remove fscrypt_select_encryption_impl(). Move the logging logic that
was previously there into fscrypt_prepare_inline_crypt_key(). Note
that blk_crypto_config_supported() is no longer needed.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
Documentation/filesystems/fscrypt.rst | 36 +++----
arch/loongarch/configs/loongson32_defconfig | 1 -
arch/loongarch/configs/loongson64_defconfig | 1 -
fs/crypto/Kconfig | 8 +-
fs/crypto/fscrypt_private.h | 21 +---
fs/crypto/inline_crypt.c | 110 ++++++--------------
fs/crypto/keysetup.c | 31 +-----
fs/ext4/crypto.c | 1 +
fs/f2fs/super.c | 1 +
include/linux/fscrypt.h | 28 ++---
10 files changed, 69 insertions(+), 169 deletions(-)
diff --git a/Documentation/filesystems/fscrypt.rst b/Documentation/filesystems/fscrypt.rst
index 92b8f311e211..370a5ef73ef2 100644
--- a/Documentation/filesystems/fscrypt.rst
+++ b/Documentation/filesystems/fscrypt.rst
@@ -1316,36 +1316,24 @@ this by validating all top-level encryption policies prior to access.
Inline encryption support
=========================
Many newer systems (especially mobile SoCs) have *inline encryption
hardware* that can encrypt/decrypt data while it is on its way to/from
-the storage device. Linux supports inline encryption through a set of
-extensions to the block layer called *blk-crypto*. blk-crypto allows
-filesystems to attach encryption contexts to bios (I/O requests) to
-specify how the data will be encrypted or decrypted in-line. For more
-information about blk-crypto, see
-:ref:`Documentation/block/inline-encryption.rst <inline_encryption>`.
+the storage device.
On supported filesystems (currently ext4 and f2fs), fscrypt can use
-blk-crypto instead of the kernel crypto API to encrypt/decrypt file
-contents. To enable this, set CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y in
-the kernel configuration, and specify the "inlinecrypt" mount option
-when mounting the filesystem.
-
-Note that the "inlinecrypt" mount option just specifies to use inline
-encryption when possible; it doesn't force its use. fscrypt will
-still fall back to using the kernel crypto API on files where the
-inline encryption hardware doesn't have the needed crypto capabilities
-(e.g. support for the needed encryption algorithm and data unit size)
-and where blk-crypto-fallback is unusable. (For blk-crypto-fallback
-to be usable, it must be enabled in the kernel configuration with
-CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y, and the file must be
-protected by a raw key rather than a hardware-wrapped key.)
-
-Currently fscrypt always uses the filesystem block size (which is
-usually 4096 bytes) as the data unit size. Therefore, it can only use
-inline encryption hardware that supports that data unit size.
+inline encryption hardware instead of the CPU to encrypt/decrypt file
+contents. To enable this, specify the "inlinecrypt" mount option when
+mounting the filesystem.
+
+This causes the filesystem to use inline encryption hardware whenever
+possible, falling back to the CPU only if such hardware is absent or
+doesn't provide the needed crypto capabilities.
+
+For more information about the kernel's support for inline encryption
+hardware, see :ref:`Documentation/block/inline-encryption.rst
+<inline_encryption>`.
Inline encryption doesn't affect the ciphertext or other aspects of
the on-disk format, so users may freely switch back and forth between
using "inlinecrypt" and not using "inlinecrypt". An exception is that
files that are protected by a hardware-wrapped key can only be
diff --git a/arch/loongarch/configs/loongson32_defconfig b/arch/loongarch/configs/loongson32_defconfig
index 7c8f01513ed2..6bf2867dbdc6 100644
--- a/arch/loongarch/configs/loongson32_defconfig
+++ b/arch/loongarch/configs/loongson32_defconfig
@@ -967,11 +967,10 @@ CONFIG_BTRFS_FS_POSIX_ACL=y
CONFIG_F2FS_FS=m
CONFIG_F2FS_FS_SECURITY=y
CONFIG_F2FS_CHECK_FS=y
CONFIG_F2FS_FS_COMPRESSION=y
CONFIG_FS_ENCRYPTION=y
-CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y
CONFIG_FS_VERITY=y
CONFIG_FANOTIFY=y
CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y
CONFIG_QUOTA=y
# CONFIG_PRINT_QUOTA_WARNING is not set
diff --git a/arch/loongarch/configs/loongson64_defconfig b/arch/loongarch/configs/loongson64_defconfig
index 8e3906d3bd70..def104c9d405 100644
--- a/arch/loongarch/configs/loongson64_defconfig
+++ b/arch/loongarch/configs/loongson64_defconfig
@@ -998,11 +998,10 @@ CONFIG_BTRFS_FS_POSIX_ACL=y
CONFIG_F2FS_FS=m
CONFIG_F2FS_FS_SECURITY=y
CONFIG_F2FS_CHECK_FS=y
CONFIG_F2FS_FS_COMPRESSION=y
CONFIG_FS_ENCRYPTION=y
-CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y
CONFIG_FS_VERITY=y
CONFIG_FANOTIFY=y
CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y
CONFIG_QUOTA=y
# CONFIG_PRINT_QUOTA_WARNING is not set
diff --git a/fs/crypto/Kconfig b/fs/crypto/Kconfig
index 983d8ad1f417..cd934e31dec4 100644
--- a/fs/crypto/Kconfig
+++ b/fs/crypto/Kconfig
@@ -1,8 +1,10 @@
# SPDX-License-Identifier: GPL-2.0-only
config FS_ENCRYPTION
bool "FS Encryption (Per-file encryption)"
+ select BLK_INLINE_ENCRYPTION if BLOCK
+ select BLK_INLINE_ENCRYPTION_FALLBACK if BLOCK
select CRYPTO
select CRYPTO_SKCIPHER
select CRYPTO_LIB_AES
select CRYPTO_LIB_SHA256
select CRYPTO_LIB_SHA512
@@ -32,9 +34,7 @@ config FS_ENCRYPTION_ALGS
select CRYPTO_CBC
select CRYPTO_CTS
select CRYPTO_XTS
config FS_ENCRYPTION_INLINE_CRYPT
- bool "Enable fscrypt to use inline crypto"
- depends on FS_ENCRYPTION && BLK_INLINE_ENCRYPTION
- help
- Enable fscrypt to use inline encryption hardware if available.
+ bool
+ default y if FS_ENCRYPTION && BLOCK
diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h
index 8234ee542476..57b7ae2cfafc 100644
--- a/fs/crypto/fscrypt_private.h
+++ b/fs/crypto/fscrypt_private.h
@@ -264,18 +264,10 @@ struct fscrypt_inode_info {
struct fscrypt_prepared_key ci_enc_key;
/* True if ci_enc_key should be freed when this struct is freed */
u8 ci_owns_key : 1;
-#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT
- /*
- * True if this inode will use inline encryption (blk-crypto) instead of
- * the traditional filesystem-layer encryption.
- */
- u8 ci_inlinecrypt : 1;
-#endif
-
/* True if ci_dirhash_key is initialized */
u8 ci_dirhash_key_initialized : 1;
/*
* log2 of the data unit size (granularity of contents encryption) of
@@ -408,17 +400,16 @@ void fscrypt_hkdf_expand(const struct hmac_sha512_key *hkdf, u8 context,
const u8 *info, unsigned int infolen,
u8 *okm, unsigned int okmlen);
/* inline_crypt.c */
#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT
-int fscrypt_select_encryption_impl(struct fscrypt_inode_info *ci,
- bool is_hw_wrapped_key);
-
static inline bool
fscrypt_using_inline_encryption(const struct fscrypt_inode_info *ci)
{
- return ci->ci_inlinecrypt;
+ const struct inode *inode = ci->ci_inode;
+
+ return S_ISREG(inode->i_mode) && inode->i_sb->s_cop->is_block_based;
}
int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
const u8 *key_bytes, size_t key_size,
bool is_hw_wrapped,
@@ -444,16 +435,10 @@ fscrypt_is_key_prepared(const struct fscrypt_prepared_key *prep_key,
return prep_key->tfm != NULL;
}
#else /* CONFIG_FS_ENCRYPTION_INLINE_CRYPT */
-static inline int fscrypt_select_encryption_impl(struct fscrypt_inode_info *ci,
- bool is_hw_wrapped_key)
-{
- return 0;
-}
-
static inline bool
fscrypt_using_inline_encryption(const struct fscrypt_inode_info *ci)
{
return false;
}
diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c
index 4f045ad1dca8..caf706215621 100644
--- a/fs/crypto/inline_crypt.c
+++ b/fs/crypto/inline_crypt.c
@@ -68,106 +68,61 @@ static unsigned int fscrypt_get_dun_bytes(const struct fscrypt_inode_info *ci)
* filesystems or files are using each implementation. However, *usually*
* systems use just one implementation per mode, which makes these messages
* helpful for debugging problems where the "wrong" implementation is used.
*/
static void fscrypt_log_blk_crypto_impl(struct fscrypt_mode *mode,
- struct block_device **devs,
- unsigned int num_devs,
- const struct blk_crypto_config *cfg)
+ struct block_device *dev,
+ const struct blk_crypto_key *blk_key)
{
- unsigned int i;
-
- for (i = 0; i < num_devs; i++) {
- if (!IS_ENABLED(CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK) ||
- blk_crypto_config_supported_natively(devs[i], cfg)) {
- if (!xchg(&mode->logged_blk_crypto_native, 1))
- pr_info("fscrypt: %s using blk-crypto (native)\n",
- mode->friendly_name);
- } else if (!xchg(&mode->logged_blk_crypto_fallback, 1)) {
- pr_info("fscrypt: %s using blk-crypto-fallback\n",
+ if (blk_crypto_config_supported_natively(dev, &blk_key->crypto_cfg)) {
+ if (!xchg(&mode->logged_blk_crypto_native, 1))
+ pr_info("fscrypt: %s using blk-crypto (native)\n",
mode->friendly_name);
- }
+ } else if (!xchg(&mode->logged_blk_crypto_fallback, 1)) {
+ pr_info("fscrypt: %s using blk-crypto-fallback\n",
+ mode->friendly_name);
}
}
-/* Enable inline encryption for this file if supported. */
-int fscrypt_select_encryption_impl(struct fscrypt_inode_info *ci,
- bool is_hw_wrapped_key)
-{
- const struct inode *inode = ci->ci_inode;
- struct super_block *sb = inode->i_sb;
- struct blk_crypto_config crypto_cfg;
- struct block_device **devs;
- unsigned int num_devs;
- unsigned int i;
-
- /* The file must need contents encryption, not filenames encryption */
- if (!S_ISREG(inode->i_mode))
- return 0;
-
- /* The crypto mode must have a blk-crypto counterpart */
- if (ci->ci_mode->blk_crypto_mode == BLK_ENCRYPTION_MODE_INVALID)
- return 0;
-
- /* The filesystem must be mounted with -o inlinecrypt */
- if (!(sb->s_flags & SB_INLINECRYPT))
- return 0;
-
- /*
- * On all the filesystem's block devices, blk-crypto must support the
- * crypto configuration that the file would use.
- */
- crypto_cfg.crypto_mode = ci->ci_mode->blk_crypto_mode;
- crypto_cfg.data_unit_size = 1U << ci->ci_data_unit_bits;
- crypto_cfg.dun_bytes = fscrypt_get_dun_bytes(ci);
- crypto_cfg.key_type = is_hw_wrapped_key ?
- BLK_CRYPTO_KEY_TYPE_HW_WRAPPED : BLK_CRYPTO_KEY_TYPE_RAW;
- crypto_cfg.allow_hw = true;
-
- devs = fscrypt_get_devices(sb, &num_devs);
- if (IS_ERR(devs))
- return PTR_ERR(devs);
-
- for (i = 0; i < num_devs; i++) {
- if (!blk_crypto_config_supported(devs[i], &crypto_cfg))
- goto out_free_devs;
- }
-
- fscrypt_log_blk_crypto_impl(ci->ci_mode, devs, num_devs, &crypto_cfg);
-
- ci->ci_inlinecrypt = true;
-out_free_devs:
- kfree(devs);
-
- return 0;
-}
-
int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
const u8 *key_bytes, size_t key_size,
bool is_hw_wrapped,
const struct fscrypt_inode_info *ci)
{
const struct inode *inode = ci->ci_inode;
struct super_block *sb = inode->i_sb;
- enum blk_crypto_mode_num crypto_mode = ci->ci_mode->blk_crypto_mode;
+ bool inlinecrypt = sb->s_flags & SB_INLINECRYPT;
+ struct fscrypt_mode *mode = ci->ci_mode;
enum blk_crypto_key_type key_type = is_hw_wrapped ?
BLK_CRYPTO_KEY_TYPE_HW_WRAPPED : BLK_CRYPTO_KEY_TYPE_RAW;
struct blk_crypto_key *blk_key;
struct block_device **devs;
unsigned int num_devs;
unsigned int i;
int err;
+ if (is_hw_wrapped && !inlinecrypt) {
+ /*
+ * blk_crypto_init_key() would catch this anyway, but this
+ * provides a clearer error message.
+ */
+ fscrypt_err(
+ inode,
+ "Hardware-wrapped keys require inline encryption (-o inlinecrypt)");
+ return -EINVAL;
+ }
+
blk_key = kmalloc_obj(*blk_key);
if (!blk_key)
return -ENOMEM;
err = blk_crypto_init_key(blk_key, key_bytes, key_size, key_type,
- crypto_mode, fscrypt_get_dun_bytes(ci),
- 1U << ci->ci_data_unit_bits, true);
+ mode->blk_crypto_mode,
+ fscrypt_get_dun_bytes(ci),
+ 1U << ci->ci_data_unit_bits, inlinecrypt);
if (err) {
- fscrypt_err(inode, "error %d initializing blk-crypto key", err);
+ fscrypt_err(inode, "Error %d initializing blk-crypto key", err);
goto fail;
}
/* Start using blk-crypto on all the filesystem's block devices. */
devs = fscrypt_get_devices(sb, &num_devs);
@@ -177,14 +132,21 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
}
for (i = 0; i < num_devs; i++) {
err = blk_crypto_start_using_key(devs[i], blk_key);
if (err)
break;
+ fscrypt_log_blk_crypto_impl(mode, devs[i], blk_key);
}
kfree(devs);
if (err) {
- fscrypt_err(inode, "error %d starting to use blk-crypto", err);
+ if (err == -EOPNOTSUPP && is_hw_wrapped)
+ fscrypt_err(
+ inode,
+ "Hardware-wrapped key required, but no suitable inline encryption capabilities are available");
+ else
+ fscrypt_err(inode,
+ "Error %d starting to use blk-crypto", err);
goto fail;
}
prep_key->blk_key = blk_key;
return 0;
@@ -241,16 +203,10 @@ int fscrypt_derive_sw_secret(struct super_block *sb,
"%s: block device doesn't support hardware-wrapped keys\n",
sb->s_id);
return err;
}
-bool __fscrypt_inode_uses_inline_crypto(const struct inode *inode)
-{
- return fscrypt_get_inode_info_raw(inode)->ci_inlinecrypt;
-}
-EXPORT_SYMBOL_GPL(__fscrypt_inode_uses_inline_crypto);
-
static void fscrypt_generate_dun(const struct fscrypt_inode_info *ci,
loff_t pos, u64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE])
{
union fscrypt_iv iv;
int i;
diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c
index cfd348e2252e..c9041f245246 100644
--- a/fs/crypto/keysetup.c
+++ b/fs/crypto/keysetup.c
@@ -142,13 +142,13 @@ fscrypt_allocate_skcipher(struct fscrypt_mode *mode, const u8 *raw_key,
return ERR_PTR(err);
}
/*
* Prepare the crypto transform object or blk-crypto key in @prep_key, given the
- * raw key, encryption mode (@ci->ci_mode), flag indicating which encryption
- * implementation (fs-layer or blk-crypto) will be used (@ci->ci_inlinecrypt),
- * and IV generation method (@ci->ci_policy.flags).
+ * raw key, encryption mode (@ci->ci_mode), predicate indicating which style of
+ * key is needed (fscrypt_using_inline_encryption(ci)), IV generation method
+ * (@ci->ci_policy.flags), and data unit size (@ci->ci_data_unit_bits).
*/
int fscrypt_prepare_key(struct fscrypt_prepared_key *prep_key,
const u8 *raw_key, const struct fscrypt_inode_info *ci)
{
struct crypto_sync_skcipher *tfm;
@@ -222,27 +222,12 @@ static int setup_per_mode_enc_key(struct fscrypt_inode_info *ci,
struct fscrypt_prepared_key *prep_key;
struct fscrypt_mode_key *new_node;
u8 raw_mode_key[FSCRYPT_MAX_RAW_KEY_SIZE];
u8 hkdf_info[sizeof(mode_num) + sizeof(sb->s_uuid)];
unsigned int hkdf_infolen = 0;
- bool use_hw_wrapped_key = false;
int err;
- if (mk->mk_secret.is_hw_wrapped && S_ISREG(inode->i_mode)) {
- /* Using a hardware-wrapped key for file contents encryption */
- if (!fscrypt_using_inline_encryption(ci)) {
- if (sb->s_flags & SB_INLINECRYPT)
- fscrypt_warn(ci->ci_inode,
- "Hardware-wrapped key required, but no suitable inline encryption capabilities are available");
- else
- fscrypt_warn(ci->ci_inode,
- "Hardware-wrapped keys require inline encryption (-o inlinecrypt)");
- return -EINVAL;
- }
- use_hw_wrapped_key = true;
- }
-
prep_key = fscrypt_find_mode_key(mk, hkdf_context, mode_num, ci);
if (prep_key) {
ci->ci_enc_key = *prep_key;
return 0;
}
@@ -261,11 +246,11 @@ static int setup_per_mode_enc_key(struct fscrypt_inode_info *ci,
new_node->hkdf_context = hkdf_context;
new_node->mode_num = mode_num;
new_node->data_unit_bits = ci->ci_data_unit_bits;
prep_key = &new_node->key;
- if (use_hw_wrapped_key) {
+ if (mk->mk_secret.is_hw_wrapped && S_ISREG(inode->i_mode)) {
err = fscrypt_prepare_inline_crypt_key(prep_key,
mk->mk_secret.bytes,
mk->mk_secret.size, true,
ci);
} else {
@@ -507,14 +492,10 @@ static int setup_file_encryption_key(struct fscrypt_inode_info *ci,
}
if (unlikely(!mk)) {
if (ci->ci_policy.version != FSCRYPT_POLICY_V1)
return -ENOKEY;
- err = fscrypt_select_encryption_impl(ci, false);
- if (err)
- return err;
-
/*
* As a legacy fallback for v1 policies, search for the key in
* the current task's subscribed keyrings too. Don't move this
* to before the search of ->s_master_keys, since users
* shouldn't be able to override filesystem-level keys.
@@ -532,14 +513,10 @@ static int setup_file_encryption_key(struct fscrypt_inode_info *ci,
if (!fscrypt_valid_master_key_size(mk, ci)) {
err = -ENOKEY;
goto out_release_key;
}
- err = fscrypt_select_encryption_impl(ci, mk->mk_secret.is_hw_wrapped);
- if (err)
- goto out_release_key;
-
switch (ci->ci_policy.version) {
case FSCRYPT_POLICY_V1:
if (WARN_ON_ONCE(mk->mk_secret.is_hw_wrapped)) {
/*
* This should never happen, as adding a v1 policy key
diff --git a/fs/ext4/crypto.c b/fs/ext4/crypto.c
index f41f320f4437..6b809ac80ef7 100644
--- a/fs/ext4/crypto.c
+++ b/fs/ext4/crypto.c
@@ -234,10 +234,11 @@ static bool ext4_has_stable_inodes(struct super_block *sb)
}
const struct fscrypt_operations ext4_cryptops = {
.inode_info_offs = (int)offsetof(struct ext4_inode_info, i_crypt_info) -
(int)offsetof(struct ext4_inode_info, vfs_inode),
+ .is_block_based = 1,
.needs_bounce_pages = 1,
.has_32bit_inodes = 1,
.supports_subblock_data_units = 1,
.legacy_key_prefix = "ext4:",
.get_context = ext4_get_context,
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index ccf806b676f5..f3f6768f8cca 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -3752,10 +3752,11 @@ static struct block_device **f2fs_get_devices(struct super_block *sb,
}
static const struct fscrypt_operations f2fs_cryptops = {
.inode_info_offs = (int)offsetof(struct f2fs_inode_info, i_crypt_info) -
(int)offsetof(struct f2fs_inode_info, vfs_inode),
+ .is_block_based = 1,
.needs_bounce_pages = 1,
.has_32bit_inodes = 1,
.supports_subblock_data_units = 1,
.legacy_key_prefix = "f2fs:",
.get_context = f2fs_get_context,
diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h
index 54712ec61ffb..8d19b95150f1 100644
--- a/include/linux/fscrypt.h
+++ b/include/linux/fscrypt.h
@@ -67,18 +67,19 @@ struct fscrypt_operations {
* the common part of the inode (the 'struct inode').
*/
ptrdiff_t inode_info_offs;
/*
- * If set, then fs/crypto/ will allocate a global bounce page pool the
- * first time an encryption key is set up for a file. The bounce page
- * pool is required by the following functions:
- *
- * - fscrypt_encrypt_pagecache_blocks()
- * - fscrypt_zeroout_range() for files not using inline crypto
- *
- * If the filesystem doesn't use those, it doesn't need to set this.
+ * Set to 1 if the filesystem is block-based. This causes fs/crypto/ to
+ * set up the key for regular files as a blk_crypto_key. The filesystem
+ * then uses fscrypt_set_bio_crypt_ctx() and similar functions.
+ */
+ unsigned int is_block_based : 1;
+
+ /*
+ * Set to 1 if the filesystem uses fscrypt_encrypt_pagecache_blocks().
+ * This enables the allocation of the bounce page pool it requires.
*/
unsigned int needs_bounce_pages : 1;
/*
* If set, then fs/crypto/ will allow the use of encryption settings
@@ -861,12 +862,10 @@ static inline void fscrypt_set_ops(struct super_block *sb,
#endif /* !CONFIG_FS_ENCRYPTION */
/* inline_crypt.c */
#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT
-bool __fscrypt_inode_uses_inline_crypto(const struct inode *inode);
-
void fscrypt_set_bio_crypt_ctx(struct bio *bio, const struct inode *inode,
loff_t pos, gfp_t gfp_mask);
bool fscrypt_mergeable_bio(struct bio *bio, const struct inode *inode,
loff_t pos);
@@ -875,15 +874,10 @@ bool fscrypt_dio_supported(struct inode *inode);
u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk, u64 nr_blocks);
#else /* CONFIG_FS_ENCRYPTION_INLINE_CRYPT */
-static inline bool __fscrypt_inode_uses_inline_crypto(const struct inode *inode)
-{
- return false;
-}
-
static inline void fscrypt_set_bio_crypt_ctx(struct bio *bio,
const struct inode *inode,
loff_t pos, gfp_t gfp_mask) { }
static inline bool fscrypt_mergeable_bio(struct bio *bio,
@@ -915,11 +909,11 @@ static inline u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk,
* than in the filesystem layer.
*/
static inline bool fscrypt_inode_uses_inline_crypto(const struct inode *inode)
{
return fscrypt_needs_contents_encryption(inode) &&
- __fscrypt_inode_uses_inline_crypto(inode);
+ inode->i_sb->s_cop->is_block_based;
}
/**
* fscrypt_inode_uses_fs_layer_crypto() - test whether an inode uses fs-layer
* encryption
@@ -930,11 +924,11 @@ static inline bool fscrypt_inode_uses_inline_crypto(const struct inode *inode)
* block layer via blk-crypto.
*/
static inline bool fscrypt_inode_uses_fs_layer_crypto(const struct inode *inode)
{
return fscrypt_needs_contents_encryption(inode) &&
- !__fscrypt_inode_uses_inline_crypto(inode);
+ !inode->i_sb->s_cop->is_block_based;
}
/**
* fscrypt_has_encryption_key() - check whether an inode has had its key set up
* @inode: the inode to check
--
2.54.0
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 06/16] ext4: Remove fs-layer file contents en/decryption code
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
-1 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: linux-fsdevel, linux-ext4, linux-f2fs-devel, linux-block,
Christoph Hellwig, Theodore Ts'o, Andreas Dilger, Baokun Li,
Jan Kara, Ojaswin Mujoo, Ritesh Harjani, Zhang Yi, Jaegeuk Kim,
Chao Yu, Eric Biggers
Now that fscrypt's file contents en/decryption is always implemented
using blk-crypto when the filesystem is block-based, the fs-layer
en/decryption code in ext4 is unused code. Remove it.
Note that this makes possible some additional cleanups, but they're left
to later commits:
- Making ext4_bio_write_folio() return void
- Renaming bio_post_read_ctx to fsverity_ctx or similar, and
allocating the pool only when fsverity support is needed
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
fs/ext4/crypto.c | 1 -
fs/ext4/inode.c | 28 ++--------------
fs/ext4/page-io.c | 68 ++-------------------------------------
fs/ext4/readpage.c | 80 ++++------------------------------------------
4 files changed, 13 insertions(+), 164 deletions(-)
diff --git a/fs/ext4/crypto.c b/fs/ext4/crypto.c
index 6b809ac80ef7..9265cfe62c83 100644
--- a/fs/ext4/crypto.c
+++ b/fs/ext4/crypto.c
@@ -235,11 +235,10 @@ static bool ext4_has_stable_inodes(struct super_block *sb)
const struct fscrypt_operations ext4_cryptops = {
.inode_info_offs = (int)offsetof(struct ext4_inode_info, i_crypt_info) -
(int)offsetof(struct ext4_inode_info, vfs_inode),
.is_block_based = 1,
- .needs_bounce_pages = 1,
.has_32bit_inodes = 1,
.supports_subblock_data_units = 1,
.legacy_key_prefix = "ext4:",
.get_context = ext4_get_context,
.set_context = ext4_set_context,
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index ce99807c5f5b..8eb2af481129 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1260,21 +1260,10 @@ int ext4_block_write_begin(handle_t *handle, struct folio *folio,
if (should_journal_data)
ext4_journalled_zero_new_buffers(handle, inode, folio,
from, to);
else
folio_zero_new_buffers(folio, from, to);
- } else if (fscrypt_inode_uses_fs_layer_crypto(inode)) {
- for (i = 0; i < nr_wait; i++) {
- int err2;
-
- err2 = fscrypt_decrypt_pagecache_blocks(folio,
- blocksize, bh_offset(wait[i]));
- if (err2) {
- clear_buffer_uptodate(wait[i]);
- err = err2;
- }
- }
}
return err;
}
@@ -3827,13 +3816,13 @@ 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.
+ * 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);
/*
* Before returning to iomap, let's ensure the allocated mapping
@@ -4079,21 +4068,10 @@ static struct buffer_head *ext4_load_tail_bh(struct inode *inode, loff_t from)
if (!buffer_uptodate(bh)) {
err = ext4_read_bh_lock(bh, 0, true);
if (err)
goto unlock;
- if (fscrypt_inode_uses_fs_layer_crypto(inode)) {
- /* We expect the key to be set. */
- BUG_ON(!fscrypt_has_encryption_key(inode));
- err = fscrypt_decrypt_pagecache_blocks(folio,
- blocksize,
- bh_offset(bh));
- if (err) {
- clear_buffer_uptodate(bh);
- goto unlock;
- }
- }
}
return bh;
unlock:
folio_unlock(folio);
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c
index bc674aa4a656..557f44178d87 100644
--- a/fs/ext4/page-io.c
+++ b/fs/ext4/page-io.c
@@ -101,22 +101,16 @@ static void ext4_finish_bio(struct bio *bio)
{
struct folio_iter fi;
bio_for_each_folio_all(fi, bio) {
struct folio *folio = fi.folio;
- struct folio *io_folio = NULL;
struct buffer_head *bh, *head;
size_t bio_start = fi.offset;
size_t bio_end = bio_start + fi.length;
unsigned under_io = 0;
unsigned long flags;
- if (fscrypt_is_bounce_folio(folio)) {
- io_folio = folio;
- folio = fscrypt_pagecache_folio(folio);
- }
-
if (bio->bi_status) {
int err = blk_status_to_errno(bio->bi_status);
mapping_set_error(folio->mapping, err);
}
bh = head = folio_buffers(folio);
@@ -137,14 +131,12 @@ static void ext4_finish_bio(struct bio *bio)
set_buffer_write_io_error(bh);
buffer_io_error(bh);
}
} while ((bh = bh->b_this_page) != head);
spin_unlock_irqrestore(&head->b_uptodate_lock, flags);
- if (!under_io) {
- fscrypt_free_bounce_page(&io_folio->page);
+ if (!under_io)
folio_end_writeback(folio);
- }
}
}
static void ext4_release_io_end(ext4_io_end_t *io_end)
{
@@ -451,33 +443,30 @@ static bool io_submit_need_new_bio(struct ext4_io_submit *io,
}
static void io_submit_add_bh(struct ext4_io_submit *io,
struct inode *inode,
struct folio *folio,
- struct folio *io_folio,
struct buffer_head *bh)
{
if (io->io_bio && io_submit_need_new_bio(io, inode, folio, bh)) {
submit_and_retry:
ext4_io_submit(io);
}
if (io->io_bio == NULL)
io_submit_init_bio(io, inode, folio, bh);
- if (!bio_add_folio(io->io_bio, io_folio, bh->b_size, bh_offset(bh)))
+ if (!bio_add_folio(io->io_bio, folio, bh->b_size, bh_offset(bh)))
goto submit_and_retry;
wbc_account_cgroup_owner(io->io_wbc, folio, bh->b_size);
io->io_next_block++;
}
int ext4_bio_write_folio(struct ext4_io_submit *io, struct folio *folio,
size_t len)
{
- struct folio *io_folio = folio;
struct inode *inode = folio->mapping->host;
unsigned block_start;
struct buffer_head *bh, *head;
- int ret = 0;
int nr_to_submit = 0;
struct writeback_control *wbc = io->io_wbc;
bool keep_towrite = false;
BUG_ON(!folio_test_locked(folio));
@@ -547,67 +536,16 @@ int ext4_bio_write_folio(struct ext4_io_submit *io, struct folio *folio,
return 0;
}
bh = head = folio_buffers(folio);
- /*
- * If any blocks are being written to an encrypted file, encrypt them
- * into a bounce page. For simplicity, just encrypt until the last
- * block which might be needed. This may cause some unneeded blocks
- * (e.g. holes) to be unnecessarily encrypted, but this is rare and
- * can't happen in the common case of blocksize == PAGE_SIZE.
- */
- if (fscrypt_inode_uses_fs_layer_crypto(inode)) {
- gfp_t gfp_flags = GFP_NOFS;
- unsigned int enc_bytes = round_up(len, i_blocksize(inode));
- struct page *bounce_page;
-
- /*
- * Since bounce page allocation uses a mempool, we can only use
- * a waiting mask (i.e. request guaranteed allocation) on the
- * first page of the bio. Otherwise it can deadlock.
- */
- if (io->io_bio)
- gfp_flags = GFP_NOWAIT;
- retry_encrypt:
- bounce_page = fscrypt_encrypt_pagecache_blocks(folio,
- enc_bytes, 0, gfp_flags);
- if (IS_ERR(bounce_page)) {
- ret = PTR_ERR(bounce_page);
- if (ret == -ENOMEM &&
- (io->io_bio || wbc->sync_mode == WB_SYNC_ALL)) {
- gfp_t new_gfp_flags = GFP_NOFS;
- if (io->io_bio)
- ext4_io_submit(io);
- else
- new_gfp_flags |= __GFP_NOFAIL;
- memalloc_retry_wait(gfp_flags);
- gfp_flags = new_gfp_flags;
- goto retry_encrypt;
- }
-
- printk_ratelimited(KERN_ERR "%s: ret = %d\n", __func__, ret);
- folio_redirty_for_writepage(wbc, folio);
- do {
- if (buffer_async_write(bh)) {
- clear_buffer_async_write(bh);
- set_buffer_dirty(bh);
- }
- bh = bh->b_this_page;
- } while (bh != head);
-
- return ret;
- }
- io_folio = page_folio(bounce_page);
- }
-
__folio_start_writeback(folio, keep_towrite);
/* Now submit buffers to write */
do {
if (!buffer_async_write(bh))
continue;
- io_submit_add_bh(io, inode, folio, io_folio, bh);
+ io_submit_add_bh(io, inode, folio, bh);
} while ((bh = bh->b_this_page) != head);
return 0;
}
diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c
index dd3627c71732..8af183798a33 100644
--- a/fs/ext4/readpage.c
+++ b/fs/ext4/readpage.c
@@ -50,24 +50,14 @@
#define NUM_PREALLOC_POST_READ_CTXS 128
static struct kmem_cache *bio_post_read_ctx_cache;
static mempool_t *bio_post_read_ctx_pool;
-/* postprocessing steps for read bios */
-enum bio_post_read_step {
- STEP_INITIAL = 0,
- STEP_DECRYPT,
- STEP_VERITY,
- STEP_MAX,
-};
-
struct bio_post_read_ctx {
struct bio *bio;
struct fsverity_info *vi;
struct work_struct work;
- unsigned int cur_step;
- unsigned int enabled_steps;
};
static void __read_end_io(struct bio *bio)
{
struct folio_iter fi;
@@ -77,80 +67,33 @@ static void __read_end_io(struct bio *bio)
if (bio->bi_private)
mempool_free(bio->bi_private, bio_post_read_ctx_pool);
bio_put(bio);
}
-static void bio_post_read_processing(struct bio_post_read_ctx *ctx);
-
-static void decrypt_work(struct work_struct *work)
-{
- struct bio_post_read_ctx *ctx =
- container_of(work, struct bio_post_read_ctx, work);
- struct bio *bio = ctx->bio;
-
- if (fscrypt_decrypt_bio(bio))
- bio_post_read_processing(ctx);
- else
- __read_end_io(bio);
-}
-
static void verity_work(struct work_struct *work)
{
struct bio_post_read_ctx *ctx =
container_of(work, struct bio_post_read_ctx, work);
struct bio *bio = ctx->bio;
struct fsverity_info *vi = ctx->vi;
/*
- * fsverity_verify_bio() may call readahead() again, and although verity
- * will be disabled for that, decryption may still be needed, causing
- * another bio_post_read_ctx to be allocated. So to guarantee that
- * mempool_alloc() never deadlocks we must free the current ctx first.
- * This is safe because verity is the last post-read step.
+ * Free the bio_post_read_ctx right away, since it's no longer needed.
+ * This relieves the pressure on the mempool as much as possible.
*/
- BUILD_BUG_ON(STEP_VERITY + 1 != STEP_MAX);
mempool_free(ctx, bio_post_read_ctx_pool);
bio->bi_private = NULL;
fsverity_verify_bio(vi, bio);
__read_end_io(bio);
}
-static void bio_post_read_processing(struct bio_post_read_ctx *ctx)
-{
- /*
- * We use different work queues for decryption and for verity because
- * verity may require reading metadata pages that need decryption, and
- * we shouldn't recurse to the same workqueue.
- */
- switch (++ctx->cur_step) {
- case STEP_DECRYPT:
- if (ctx->enabled_steps & (1 << STEP_DECRYPT)) {
- INIT_WORK(&ctx->work, decrypt_work);
- fscrypt_enqueue_decrypt_work(&ctx->work);
- return;
- }
- ctx->cur_step++;
- fallthrough;
- case STEP_VERITY:
- if (IS_ENABLED(CONFIG_FS_VERITY) &&
- ctx->enabled_steps & (1 << STEP_VERITY)) {
- INIT_WORK(&ctx->work, verity_work);
- fsverity_enqueue_verify_work(&ctx->work);
- return;
- }
- ctx->cur_step++;
- fallthrough;
- default:
- __read_end_io(ctx->bio);
- }
-}
-
static bool bio_post_read_required(struct bio *bio)
{
- return bio->bi_private && !bio->bi_status;
+ return IS_ENABLED(CONFIG_FS_VERITY) && bio->bi_private &&
+ !bio->bi_status;
}
/*
* I/O completion handler for multipage BIOs.
*
@@ -166,37 +109,28 @@ static bool bio_post_read_required(struct bio *bio)
static void mpage_end_io(struct bio *bio)
{
if (bio_post_read_required(bio)) {
struct bio_post_read_ctx *ctx = bio->bi_private;
- ctx->cur_step = STEP_INITIAL;
- bio_post_read_processing(ctx);
+ INIT_WORK(&ctx->work, verity_work);
+ fsverity_enqueue_verify_work(&ctx->work);
return;
}
__read_end_io(bio);
}
static void ext4_set_bio_post_read_ctx(struct bio *bio,
const struct inode *inode,
struct fsverity_info *vi)
{
- unsigned int post_read_steps = 0;
-
- if (fscrypt_inode_uses_fs_layer_crypto(inode))
- post_read_steps |= 1 << STEP_DECRYPT;
-
- if (vi)
- post_read_steps |= 1 << STEP_VERITY;
-
- if (post_read_steps) {
+ if (vi) {
/* Due to the mempool, this never fails. */
struct bio_post_read_ctx *ctx =
mempool_alloc(bio_post_read_ctx_pool, GFP_NOFS);
ctx->bio = bio;
ctx->vi = vi;
- ctx->enabled_steps = post_read_steps;
bio->bi_private = ctx;
}
}
static inline loff_t ext4_readpage_limit(struct inode *inode)
--
2.54.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [f2fs-dev] [PATCH 06/16] ext4: Remove fs-layer file contents en/decryption code
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
0 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers via Linux-f2fs-devel @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: Ritesh Harjani, Theodore Ts'o, Zhang Yi, linux-f2fs-devel,
linux-block, Andreas Dilger, Ojaswin Mujoo, Baokun Li,
Jaegeuk Kim, linux-fsdevel, Jan Kara, linux-ext4,
Christoph Hellwig, Eric Biggers
Now that fscrypt's file contents en/decryption is always implemented
using blk-crypto when the filesystem is block-based, the fs-layer
en/decryption code in ext4 is unused code. Remove it.
Note that this makes possible some additional cleanups, but they're left
to later commits:
- Making ext4_bio_write_folio() return void
- Renaming bio_post_read_ctx to fsverity_ctx or similar, and
allocating the pool only when fsverity support is needed
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
fs/ext4/crypto.c | 1 -
fs/ext4/inode.c | 28 ++--------------
fs/ext4/page-io.c | 68 ++-------------------------------------
fs/ext4/readpage.c | 80 ++++------------------------------------------
4 files changed, 13 insertions(+), 164 deletions(-)
diff --git a/fs/ext4/crypto.c b/fs/ext4/crypto.c
index 6b809ac80ef7..9265cfe62c83 100644
--- a/fs/ext4/crypto.c
+++ b/fs/ext4/crypto.c
@@ -235,11 +235,10 @@ static bool ext4_has_stable_inodes(struct super_block *sb)
const struct fscrypt_operations ext4_cryptops = {
.inode_info_offs = (int)offsetof(struct ext4_inode_info, i_crypt_info) -
(int)offsetof(struct ext4_inode_info, vfs_inode),
.is_block_based = 1,
- .needs_bounce_pages = 1,
.has_32bit_inodes = 1,
.supports_subblock_data_units = 1,
.legacy_key_prefix = "ext4:",
.get_context = ext4_get_context,
.set_context = ext4_set_context,
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index ce99807c5f5b..8eb2af481129 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1260,21 +1260,10 @@ int ext4_block_write_begin(handle_t *handle, struct folio *folio,
if (should_journal_data)
ext4_journalled_zero_new_buffers(handle, inode, folio,
from, to);
else
folio_zero_new_buffers(folio, from, to);
- } else if (fscrypt_inode_uses_fs_layer_crypto(inode)) {
- for (i = 0; i < nr_wait; i++) {
- int err2;
-
- err2 = fscrypt_decrypt_pagecache_blocks(folio,
- blocksize, bh_offset(wait[i]));
- if (err2) {
- clear_buffer_uptodate(wait[i]);
- err = err2;
- }
- }
}
return err;
}
@@ -3827,13 +3816,13 @@ 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.
+ * 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);
/*
* Before returning to iomap, let's ensure the allocated mapping
@@ -4079,21 +4068,10 @@ static struct buffer_head *ext4_load_tail_bh(struct inode *inode, loff_t from)
if (!buffer_uptodate(bh)) {
err = ext4_read_bh_lock(bh, 0, true);
if (err)
goto unlock;
- if (fscrypt_inode_uses_fs_layer_crypto(inode)) {
- /* We expect the key to be set. */
- BUG_ON(!fscrypt_has_encryption_key(inode));
- err = fscrypt_decrypt_pagecache_blocks(folio,
- blocksize,
- bh_offset(bh));
- if (err) {
- clear_buffer_uptodate(bh);
- goto unlock;
- }
- }
}
return bh;
unlock:
folio_unlock(folio);
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c
index bc674aa4a656..557f44178d87 100644
--- a/fs/ext4/page-io.c
+++ b/fs/ext4/page-io.c
@@ -101,22 +101,16 @@ static void ext4_finish_bio(struct bio *bio)
{
struct folio_iter fi;
bio_for_each_folio_all(fi, bio) {
struct folio *folio = fi.folio;
- struct folio *io_folio = NULL;
struct buffer_head *bh, *head;
size_t bio_start = fi.offset;
size_t bio_end = bio_start + fi.length;
unsigned under_io = 0;
unsigned long flags;
- if (fscrypt_is_bounce_folio(folio)) {
- io_folio = folio;
- folio = fscrypt_pagecache_folio(folio);
- }
-
if (bio->bi_status) {
int err = blk_status_to_errno(bio->bi_status);
mapping_set_error(folio->mapping, err);
}
bh = head = folio_buffers(folio);
@@ -137,14 +131,12 @@ static void ext4_finish_bio(struct bio *bio)
set_buffer_write_io_error(bh);
buffer_io_error(bh);
}
} while ((bh = bh->b_this_page) != head);
spin_unlock_irqrestore(&head->b_uptodate_lock, flags);
- if (!under_io) {
- fscrypt_free_bounce_page(&io_folio->page);
+ if (!under_io)
folio_end_writeback(folio);
- }
}
}
static void ext4_release_io_end(ext4_io_end_t *io_end)
{
@@ -451,33 +443,30 @@ static bool io_submit_need_new_bio(struct ext4_io_submit *io,
}
static void io_submit_add_bh(struct ext4_io_submit *io,
struct inode *inode,
struct folio *folio,
- struct folio *io_folio,
struct buffer_head *bh)
{
if (io->io_bio && io_submit_need_new_bio(io, inode, folio, bh)) {
submit_and_retry:
ext4_io_submit(io);
}
if (io->io_bio == NULL)
io_submit_init_bio(io, inode, folio, bh);
- if (!bio_add_folio(io->io_bio, io_folio, bh->b_size, bh_offset(bh)))
+ if (!bio_add_folio(io->io_bio, folio, bh->b_size, bh_offset(bh)))
goto submit_and_retry;
wbc_account_cgroup_owner(io->io_wbc, folio, bh->b_size);
io->io_next_block++;
}
int ext4_bio_write_folio(struct ext4_io_submit *io, struct folio *folio,
size_t len)
{
- struct folio *io_folio = folio;
struct inode *inode = folio->mapping->host;
unsigned block_start;
struct buffer_head *bh, *head;
- int ret = 0;
int nr_to_submit = 0;
struct writeback_control *wbc = io->io_wbc;
bool keep_towrite = false;
BUG_ON(!folio_test_locked(folio));
@@ -547,67 +536,16 @@ int ext4_bio_write_folio(struct ext4_io_submit *io, struct folio *folio,
return 0;
}
bh = head = folio_buffers(folio);
- /*
- * If any blocks are being written to an encrypted file, encrypt them
- * into a bounce page. For simplicity, just encrypt until the last
- * block which might be needed. This may cause some unneeded blocks
- * (e.g. holes) to be unnecessarily encrypted, but this is rare and
- * can't happen in the common case of blocksize == PAGE_SIZE.
- */
- if (fscrypt_inode_uses_fs_layer_crypto(inode)) {
- gfp_t gfp_flags = GFP_NOFS;
- unsigned int enc_bytes = round_up(len, i_blocksize(inode));
- struct page *bounce_page;
-
- /*
- * Since bounce page allocation uses a mempool, we can only use
- * a waiting mask (i.e. request guaranteed allocation) on the
- * first page of the bio. Otherwise it can deadlock.
- */
- if (io->io_bio)
- gfp_flags = GFP_NOWAIT;
- retry_encrypt:
- bounce_page = fscrypt_encrypt_pagecache_blocks(folio,
- enc_bytes, 0, gfp_flags);
- if (IS_ERR(bounce_page)) {
- ret = PTR_ERR(bounce_page);
- if (ret == -ENOMEM &&
- (io->io_bio || wbc->sync_mode == WB_SYNC_ALL)) {
- gfp_t new_gfp_flags = GFP_NOFS;
- if (io->io_bio)
- ext4_io_submit(io);
- else
- new_gfp_flags |= __GFP_NOFAIL;
- memalloc_retry_wait(gfp_flags);
- gfp_flags = new_gfp_flags;
- goto retry_encrypt;
- }
-
- printk_ratelimited(KERN_ERR "%s: ret = %d\n", __func__, ret);
- folio_redirty_for_writepage(wbc, folio);
- do {
- if (buffer_async_write(bh)) {
- clear_buffer_async_write(bh);
- set_buffer_dirty(bh);
- }
- bh = bh->b_this_page;
- } while (bh != head);
-
- return ret;
- }
- io_folio = page_folio(bounce_page);
- }
-
__folio_start_writeback(folio, keep_towrite);
/* Now submit buffers to write */
do {
if (!buffer_async_write(bh))
continue;
- io_submit_add_bh(io, inode, folio, io_folio, bh);
+ io_submit_add_bh(io, inode, folio, bh);
} while ((bh = bh->b_this_page) != head);
return 0;
}
diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c
index dd3627c71732..8af183798a33 100644
--- a/fs/ext4/readpage.c
+++ b/fs/ext4/readpage.c
@@ -50,24 +50,14 @@
#define NUM_PREALLOC_POST_READ_CTXS 128
static struct kmem_cache *bio_post_read_ctx_cache;
static mempool_t *bio_post_read_ctx_pool;
-/* postprocessing steps for read bios */
-enum bio_post_read_step {
- STEP_INITIAL = 0,
- STEP_DECRYPT,
- STEP_VERITY,
- STEP_MAX,
-};
-
struct bio_post_read_ctx {
struct bio *bio;
struct fsverity_info *vi;
struct work_struct work;
- unsigned int cur_step;
- unsigned int enabled_steps;
};
static void __read_end_io(struct bio *bio)
{
struct folio_iter fi;
@@ -77,80 +67,33 @@ static void __read_end_io(struct bio *bio)
if (bio->bi_private)
mempool_free(bio->bi_private, bio_post_read_ctx_pool);
bio_put(bio);
}
-static void bio_post_read_processing(struct bio_post_read_ctx *ctx);
-
-static void decrypt_work(struct work_struct *work)
-{
- struct bio_post_read_ctx *ctx =
- container_of(work, struct bio_post_read_ctx, work);
- struct bio *bio = ctx->bio;
-
- if (fscrypt_decrypt_bio(bio))
- bio_post_read_processing(ctx);
- else
- __read_end_io(bio);
-}
-
static void verity_work(struct work_struct *work)
{
struct bio_post_read_ctx *ctx =
container_of(work, struct bio_post_read_ctx, work);
struct bio *bio = ctx->bio;
struct fsverity_info *vi = ctx->vi;
/*
- * fsverity_verify_bio() may call readahead() again, and although verity
- * will be disabled for that, decryption may still be needed, causing
- * another bio_post_read_ctx to be allocated. So to guarantee that
- * mempool_alloc() never deadlocks we must free the current ctx first.
- * This is safe because verity is the last post-read step.
+ * Free the bio_post_read_ctx right away, since it's no longer needed.
+ * This relieves the pressure on the mempool as much as possible.
*/
- BUILD_BUG_ON(STEP_VERITY + 1 != STEP_MAX);
mempool_free(ctx, bio_post_read_ctx_pool);
bio->bi_private = NULL;
fsverity_verify_bio(vi, bio);
__read_end_io(bio);
}
-static void bio_post_read_processing(struct bio_post_read_ctx *ctx)
-{
- /*
- * We use different work queues for decryption and for verity because
- * verity may require reading metadata pages that need decryption, and
- * we shouldn't recurse to the same workqueue.
- */
- switch (++ctx->cur_step) {
- case STEP_DECRYPT:
- if (ctx->enabled_steps & (1 << STEP_DECRYPT)) {
- INIT_WORK(&ctx->work, decrypt_work);
- fscrypt_enqueue_decrypt_work(&ctx->work);
- return;
- }
- ctx->cur_step++;
- fallthrough;
- case STEP_VERITY:
- if (IS_ENABLED(CONFIG_FS_VERITY) &&
- ctx->enabled_steps & (1 << STEP_VERITY)) {
- INIT_WORK(&ctx->work, verity_work);
- fsverity_enqueue_verify_work(&ctx->work);
- return;
- }
- ctx->cur_step++;
- fallthrough;
- default:
- __read_end_io(ctx->bio);
- }
-}
-
static bool bio_post_read_required(struct bio *bio)
{
- return bio->bi_private && !bio->bi_status;
+ return IS_ENABLED(CONFIG_FS_VERITY) && bio->bi_private &&
+ !bio->bi_status;
}
/*
* I/O completion handler for multipage BIOs.
*
@@ -166,37 +109,28 @@ static bool bio_post_read_required(struct bio *bio)
static void mpage_end_io(struct bio *bio)
{
if (bio_post_read_required(bio)) {
struct bio_post_read_ctx *ctx = bio->bi_private;
- ctx->cur_step = STEP_INITIAL;
- bio_post_read_processing(ctx);
+ INIT_WORK(&ctx->work, verity_work);
+ fsverity_enqueue_verify_work(&ctx->work);
return;
}
__read_end_io(bio);
}
static void ext4_set_bio_post_read_ctx(struct bio *bio,
const struct inode *inode,
struct fsverity_info *vi)
{
- unsigned int post_read_steps = 0;
-
- if (fscrypt_inode_uses_fs_layer_crypto(inode))
- post_read_steps |= 1 << STEP_DECRYPT;
-
- if (vi)
- post_read_steps |= 1 << STEP_VERITY;
-
- if (post_read_steps) {
+ if (vi) {
/* Due to the mempool, this never fails. */
struct bio_post_read_ctx *ctx =
mempool_alloc(bio_post_read_ctx_pool, GFP_NOFS);
ctx->bio = bio;
ctx->vi = vi;
- ctx->enabled_steps = post_read_steps;
bio->bi_private = ctx;
}
}
static inline loff_t ext4_readpage_limit(struct inode *inode)
--
2.54.0
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 07/16] ext4: Make ext4_bio_write_folio() return void
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
-1 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: linux-fsdevel, linux-ext4, linux-f2fs-devel, linux-block,
Christoph Hellwig, Theodore Ts'o, Andreas Dilger, Baokun Li,
Jan Kara, Ojaswin Mujoo, Ritesh Harjani, Zhang Yi, Jaegeuk Kim,
Chao Yu, Eric Biggers
Since the fs-layer file contents encryption implementation was removed,
ext4_bio_write_folio() now always returns 0. Change it to return void,
and likewise for its caller mpage_submit_folio().
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
fs/ext4/ext4.h | 2 +-
fs/ext4/inode.c | 31 ++++++++-----------------------
fs/ext4/page-io.c | 6 ++----
3 files changed, 11 insertions(+), 28 deletions(-)
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index b37c136ea3ab..920a8ec1b948 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -3943,11 +3943,11 @@ extern int ext4_put_io_end(ext4_io_end_t *io_end);
extern void ext4_put_io_end_defer(ext4_io_end_t *io_end);
extern void ext4_io_submit_init(struct ext4_io_submit *io,
struct writeback_control *wbc);
extern void ext4_end_io_rsv_work(struct work_struct *work);
extern void ext4_io_submit(struct ext4_io_submit *io);
-int ext4_bio_write_folio(struct ext4_io_submit *io, struct folio *page,
+void ext4_bio_write_folio(struct ext4_io_submit *io, struct folio *page,
size_t len);
extern struct ext4_io_end_vec *ext4_alloc_io_end_vec(ext4_io_end_t *io_end);
extern struct ext4_io_end_vec *ext4_last_io_end_vec(ext4_io_end_t *io_end);
/* mmp.c */
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 8eb2af481129..c6faa7c751ca 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -2062,15 +2062,14 @@ static void mpage_folio_done(struct mpage_da_data *mpd, struct folio *folio)
mpd->start_pos += folio_size(folio);
mpd->wbc->nr_to_write -= folio_nr_pages(folio);
folio_unlock(folio);
}
-static int mpage_submit_folio(struct mpage_da_data *mpd, struct folio *folio)
+static void mpage_submit_folio(struct mpage_da_data *mpd, struct folio *folio)
{
size_t len;
loff_t size;
- int err;
WARN_ON_ONCE(folio_pos(folio) != mpd->start_pos);
folio_clear_dirty_for_io(folio);
/*
* We have to be very careful here! Nothing protects writeback path
@@ -2088,13 +2087,11 @@ static int mpage_submit_folio(struct mpage_da_data *mpd, struct folio *folio)
size = i_size_read(mpd->inode);
len = folio_size(folio);
if (folio_pos(folio) + len > size &&
!ext4_verity_in_progress(mpd->inode))
len = size & (len - 1);
- err = ext4_bio_write_folio(&mpd->io_submit, folio, len);
-
- return err;
+ ext4_bio_write_folio(&mpd->io_submit, folio, len);
}
#define BH_FLAGS (BIT(BH_Unwritten) | BIT(BH_Delay))
/*
@@ -2167,20 +2164,18 @@ static bool mpage_add_bh_to_extent(struct mpage_da_data *mpd, ext4_lblk_t lblk,
* Walk through page buffers from @bh upto @head (exclusive) and either submit
* the page for IO if all buffers in this page were mapped and there's no
* accumulated extent of buffers to map or add buffers in the page to the
* extent of buffers to map. The function returns 1 if the caller can continue
* by processing the next page, 0 if it should stop adding buffers to the
- * extent to map because we cannot extend it anymore. It can also return value
- * < 0 in case of error during IO submission.
+ * extent to map because we cannot extend it anymore.
*/
static int mpage_process_page_bufs(struct mpage_da_data *mpd,
struct buffer_head *head,
struct buffer_head *bh,
ext4_lblk_t lblk)
{
struct inode *inode = mpd->inode;
- int err;
ext4_lblk_t blocks = (i_size_read(inode) + i_blocksize(inode) - 1)
>> inode->i_blkbits;
if (ext4_verity_in_progress(inode))
blocks = EXT_MAX_BLOCKS;
@@ -2199,13 +2194,11 @@ static int mpage_process_page_bufs(struct mpage_da_data *mpd,
break;
}
} while (lblk++, (bh = bh->b_this_page) != head);
/* So far everything mapped? Submit the page for IO. */
if (mpd->map.m_len == 0) {
- err = mpage_submit_folio(mpd, head->b_folio);
- if (err < 0)
- return err;
+ mpage_submit_folio(mpd, head->b_folio);
mpage_folio_done(mpd, head->b_folio);
}
if (lblk >= blocks) {
mpd->scanned_until_end = 1;
return 0;
@@ -2331,13 +2324,11 @@ static int mpage_map_and_submit_buffers(struct mpage_da_data *mpd)
* So we return to call further extent mapping.
*/
if (err < 0 || map_bh)
goto out;
/* Page fully mapped - let IO run! */
- err = mpage_submit_folio(mpd, folio);
- if (err < 0)
- goto out;
+ mpage_submit_folio(mpd, folio);
mpage_folio_done(mpd, folio);
}
folio_batch_release(&fbatch);
}
/* Extent fully mapped and matches with page boundary. We are done. */
@@ -2406,11 +2397,10 @@ static int mpage_map_one_extent(handle_t *handle, struct mpage_da_data *mpd)
static int mpage_submit_partial_folio(struct mpage_da_data *mpd)
{
struct inode *inode = mpd->inode;
struct folio *folio;
loff_t pos;
- int ret;
folio = filemap_get_folio(inode->i_mapping,
mpd->start_pos >> PAGE_SHIFT);
if (IS_ERR(folio))
return PTR_ERR(folio);
@@ -2421,25 +2411,22 @@ static int mpage_submit_partial_folio(struct mpage_da_data *mpd)
pos = ((loff_t)mpd->map.m_lblk) << inode->i_blkbits;
if (WARN_ON_ONCE((folio_pos(folio) == pos) ||
!folio_contains(folio, pos >> PAGE_SHIFT)))
return -EINVAL;
- ret = mpage_submit_folio(mpd, folio);
- if (ret)
- goto out;
+ mpage_submit_folio(mpd, folio);
/*
* Update start_pos to prevent this folio from being released in
* mpage_release_unused_pages(), it will be reset to the aligned folio
* pos when this folio is written again in the next round. Additionally,
* do not update wbc->nr_to_write here, as it will be updated once the
* entire folio has finished processing.
*/
mpd->start_pos = pos;
-out:
folio_unlock(folio);
folio_put(folio);
- return ret;
+ return 0;
}
/*
* mpage_map_and_submit_extent - map extent starting at mpd->lblk of length
* mpd->len and submit pages underlying it for IO
@@ -2722,13 +2709,11 @@ static int mpage_prepare_extent_to_map(struct mpage_da_data *mpd)
* location before possibly journalling it again which
* is desirable when the page is frequently dirtied
* through a pin.
*/
if (!mpd->can_map) {
- err = mpage_submit_folio(mpd, folio);
- if (err < 0)
- goto out;
+ mpage_submit_folio(mpd, folio);
/* Pending dirtying of journalled data? */
if (folio_test_checked(folio)) {
err = mpage_journal_page_buffers(handle,
mpd, folio);
if (err < 0)
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c
index 557f44178d87..0236b6b9785a 100644
--- a/fs/ext4/page-io.c
+++ b/fs/ext4/page-io.c
@@ -457,11 +457,11 @@ static void io_submit_add_bh(struct ext4_io_submit *io,
goto submit_and_retry;
wbc_account_cgroup_owner(io->io_wbc, folio, bh->b_size);
io->io_next_block++;
}
-int ext4_bio_write_folio(struct ext4_io_submit *io, struct folio *folio,
+void ext4_bio_write_folio(struct ext4_io_submit *io, struct folio *folio,
size_t len)
{
struct inode *inode = folio->mapping->host;
unsigned block_start;
struct buffer_head *bh, *head;
@@ -531,11 +531,11 @@ int ext4_bio_write_folio(struct ext4_io_submit *io, struct folio *folio,
* We have nothing to submit. Just cycle the folio through
* writeback state to properly update xarray tags.
*/
__folio_start_writeback(folio, keep_towrite);
folio_end_writeback(folio);
- return 0;
+ return;
}
bh = head = folio_buffers(folio);
__folio_start_writeback(folio, keep_towrite);
@@ -544,8 +544,6 @@ int ext4_bio_write_folio(struct ext4_io_submit *io, struct folio *folio,
do {
if (!buffer_async_write(bh))
continue;
io_submit_add_bh(io, inode, folio, bh);
} while ((bh = bh->b_this_page) != head);
-
- return 0;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [f2fs-dev] [PATCH 07/16] ext4: Make ext4_bio_write_folio() return void
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
0 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers via Linux-f2fs-devel @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: Ritesh Harjani, Theodore Ts'o, Zhang Yi, linux-f2fs-devel,
linux-block, Andreas Dilger, Ojaswin Mujoo, Baokun Li,
Jaegeuk Kim, linux-fsdevel, Jan Kara, linux-ext4,
Christoph Hellwig, Eric Biggers
Since the fs-layer file contents encryption implementation was removed,
ext4_bio_write_folio() now always returns 0. Change it to return void,
and likewise for its caller mpage_submit_folio().
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
fs/ext4/ext4.h | 2 +-
fs/ext4/inode.c | 31 ++++++++-----------------------
fs/ext4/page-io.c | 6 ++----
3 files changed, 11 insertions(+), 28 deletions(-)
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index b37c136ea3ab..920a8ec1b948 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -3943,11 +3943,11 @@ extern int ext4_put_io_end(ext4_io_end_t *io_end);
extern void ext4_put_io_end_defer(ext4_io_end_t *io_end);
extern void ext4_io_submit_init(struct ext4_io_submit *io,
struct writeback_control *wbc);
extern void ext4_end_io_rsv_work(struct work_struct *work);
extern void ext4_io_submit(struct ext4_io_submit *io);
-int ext4_bio_write_folio(struct ext4_io_submit *io, struct folio *page,
+void ext4_bio_write_folio(struct ext4_io_submit *io, struct folio *page,
size_t len);
extern struct ext4_io_end_vec *ext4_alloc_io_end_vec(ext4_io_end_t *io_end);
extern struct ext4_io_end_vec *ext4_last_io_end_vec(ext4_io_end_t *io_end);
/* mmp.c */
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 8eb2af481129..c6faa7c751ca 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -2062,15 +2062,14 @@ static void mpage_folio_done(struct mpage_da_data *mpd, struct folio *folio)
mpd->start_pos += folio_size(folio);
mpd->wbc->nr_to_write -= folio_nr_pages(folio);
folio_unlock(folio);
}
-static int mpage_submit_folio(struct mpage_da_data *mpd, struct folio *folio)
+static void mpage_submit_folio(struct mpage_da_data *mpd, struct folio *folio)
{
size_t len;
loff_t size;
- int err;
WARN_ON_ONCE(folio_pos(folio) != mpd->start_pos);
folio_clear_dirty_for_io(folio);
/*
* We have to be very careful here! Nothing protects writeback path
@@ -2088,13 +2087,11 @@ static int mpage_submit_folio(struct mpage_da_data *mpd, struct folio *folio)
size = i_size_read(mpd->inode);
len = folio_size(folio);
if (folio_pos(folio) + len > size &&
!ext4_verity_in_progress(mpd->inode))
len = size & (len - 1);
- err = ext4_bio_write_folio(&mpd->io_submit, folio, len);
-
- return err;
+ ext4_bio_write_folio(&mpd->io_submit, folio, len);
}
#define BH_FLAGS (BIT(BH_Unwritten) | BIT(BH_Delay))
/*
@@ -2167,20 +2164,18 @@ static bool mpage_add_bh_to_extent(struct mpage_da_data *mpd, ext4_lblk_t lblk,
* Walk through page buffers from @bh upto @head (exclusive) and either submit
* the page for IO if all buffers in this page were mapped and there's no
* accumulated extent of buffers to map or add buffers in the page to the
* extent of buffers to map. The function returns 1 if the caller can continue
* by processing the next page, 0 if it should stop adding buffers to the
- * extent to map because we cannot extend it anymore. It can also return value
- * < 0 in case of error during IO submission.
+ * extent to map because we cannot extend it anymore.
*/
static int mpage_process_page_bufs(struct mpage_da_data *mpd,
struct buffer_head *head,
struct buffer_head *bh,
ext4_lblk_t lblk)
{
struct inode *inode = mpd->inode;
- int err;
ext4_lblk_t blocks = (i_size_read(inode) + i_blocksize(inode) - 1)
>> inode->i_blkbits;
if (ext4_verity_in_progress(inode))
blocks = EXT_MAX_BLOCKS;
@@ -2199,13 +2194,11 @@ static int mpage_process_page_bufs(struct mpage_da_data *mpd,
break;
}
} while (lblk++, (bh = bh->b_this_page) != head);
/* So far everything mapped? Submit the page for IO. */
if (mpd->map.m_len == 0) {
- err = mpage_submit_folio(mpd, head->b_folio);
- if (err < 0)
- return err;
+ mpage_submit_folio(mpd, head->b_folio);
mpage_folio_done(mpd, head->b_folio);
}
if (lblk >= blocks) {
mpd->scanned_until_end = 1;
return 0;
@@ -2331,13 +2324,11 @@ static int mpage_map_and_submit_buffers(struct mpage_da_data *mpd)
* So we return to call further extent mapping.
*/
if (err < 0 || map_bh)
goto out;
/* Page fully mapped - let IO run! */
- err = mpage_submit_folio(mpd, folio);
- if (err < 0)
- goto out;
+ mpage_submit_folio(mpd, folio);
mpage_folio_done(mpd, folio);
}
folio_batch_release(&fbatch);
}
/* Extent fully mapped and matches with page boundary. We are done. */
@@ -2406,11 +2397,10 @@ static int mpage_map_one_extent(handle_t *handle, struct mpage_da_data *mpd)
static int mpage_submit_partial_folio(struct mpage_da_data *mpd)
{
struct inode *inode = mpd->inode;
struct folio *folio;
loff_t pos;
- int ret;
folio = filemap_get_folio(inode->i_mapping,
mpd->start_pos >> PAGE_SHIFT);
if (IS_ERR(folio))
return PTR_ERR(folio);
@@ -2421,25 +2411,22 @@ static int mpage_submit_partial_folio(struct mpage_da_data *mpd)
pos = ((loff_t)mpd->map.m_lblk) << inode->i_blkbits;
if (WARN_ON_ONCE((folio_pos(folio) == pos) ||
!folio_contains(folio, pos >> PAGE_SHIFT)))
return -EINVAL;
- ret = mpage_submit_folio(mpd, folio);
- if (ret)
- goto out;
+ mpage_submit_folio(mpd, folio);
/*
* Update start_pos to prevent this folio from being released in
* mpage_release_unused_pages(), it will be reset to the aligned folio
* pos when this folio is written again in the next round. Additionally,
* do not update wbc->nr_to_write here, as it will be updated once the
* entire folio has finished processing.
*/
mpd->start_pos = pos;
-out:
folio_unlock(folio);
folio_put(folio);
- return ret;
+ return 0;
}
/*
* mpage_map_and_submit_extent - map extent starting at mpd->lblk of length
* mpd->len and submit pages underlying it for IO
@@ -2722,13 +2709,11 @@ static int mpage_prepare_extent_to_map(struct mpage_da_data *mpd)
* location before possibly journalling it again which
* is desirable when the page is frequently dirtied
* through a pin.
*/
if (!mpd->can_map) {
- err = mpage_submit_folio(mpd, folio);
- if (err < 0)
- goto out;
+ mpage_submit_folio(mpd, folio);
/* Pending dirtying of journalled data? */
if (folio_test_checked(folio)) {
err = mpage_journal_page_buffers(handle,
mpd, folio);
if (err < 0)
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c
index 557f44178d87..0236b6b9785a 100644
--- a/fs/ext4/page-io.c
+++ b/fs/ext4/page-io.c
@@ -457,11 +457,11 @@ static void io_submit_add_bh(struct ext4_io_submit *io,
goto submit_and_retry;
wbc_account_cgroup_owner(io->io_wbc, folio, bh->b_size);
io->io_next_block++;
}
-int ext4_bio_write_folio(struct ext4_io_submit *io, struct folio *folio,
+void ext4_bio_write_folio(struct ext4_io_submit *io, struct folio *folio,
size_t len)
{
struct inode *inode = folio->mapping->host;
unsigned block_start;
struct buffer_head *bh, *head;
@@ -531,11 +531,11 @@ int ext4_bio_write_folio(struct ext4_io_submit *io, struct folio *folio,
* We have nothing to submit. Just cycle the folio through
* writeback state to properly update xarray tags.
*/
__folio_start_writeback(folio, keep_towrite);
folio_end_writeback(folio);
- return 0;
+ return;
}
bh = head = folio_buffers(folio);
__folio_start_writeback(folio, keep_towrite);
@@ -544,8 +544,6 @@ int ext4_bio_write_folio(struct ext4_io_submit *io, struct folio *folio,
do {
if (!buffer_async_write(bh))
continue;
io_submit_add_bh(io, inode, folio, bh);
} while ((bh = bh->b_this_page) != head);
-
- return 0;
}
--
2.54.0
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 08/16] ext4: Further de-generalize the bio postprocessing code
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
-1 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: linux-fsdevel, linux-ext4, linux-f2fs-devel, linux-block,
Christoph Hellwig, Theodore Ts'o, Andreas Dilger, Baokun Li,
Jan Kara, Ojaswin Mujoo, Ritesh Harjani, Zhang Yi, Jaegeuk Kim,
Chao Yu, Eric Biggers
Since the bio postprocessing code in fs/ext4/readpage.c is now used only
for fsverity, rename things accordingly. Also don't create the caches
at all when !CONFIG_FS_VERITY.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
fs/ext4/ext4.h | 4 +--
fs/ext4/readpage.c | 66 ++++++++++++++++++++++------------------------
fs/ext4/super.c | 6 ++---
3 files changed, 37 insertions(+), 39 deletions(-)
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 920a8ec1b948..af6cf0bbc5e2 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -3827,12 +3827,12 @@ static inline void ext4_set_de_type(struct super_block *sb,
}
/* readpages.c */
int ext4_read_folio(struct file *file, struct folio *folio);
void ext4_readahead(struct readahead_control *rac);
-extern int __init ext4_init_post_read_processing(void);
-extern void ext4_exit_post_read_processing(void);
+extern int __init ext4_init_verity_caches(void);
+extern void ext4_exit_verity_caches(void);
/* symlink.c */
extern const struct inode_operations ext4_encrypted_symlink_inode_operations;
extern const struct inode_operations ext4_symlink_inode_operations;
extern const struct inode_operations ext4_fast_symlink_inode_operations;
diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c
index 8af183798a33..322226290e65 100644
--- a/fs/ext4/readpage.c
+++ b/fs/ext4/readpage.c
@@ -45,16 +45,16 @@
#include <linux/backing-dev.h>
#include "ext4.h"
#include <trace/events/ext4.h>
-#define NUM_PREALLOC_POST_READ_CTXS 128
+#define NUM_VERITY_WORKS 128
-static struct kmem_cache *bio_post_read_ctx_cache;
-static mempool_t *bio_post_read_ctx_pool;
+static struct kmem_cache *ext4_verity_work_cache;
+static mempool_t *ext4_verity_work_pool;
-struct bio_post_read_ctx {
+struct ext4_verity_work {
struct bio *bio;
struct fsverity_info *vi;
struct work_struct work;
};
@@ -63,39 +63,33 @@ static void __read_end_io(struct bio *bio)
struct folio_iter fi;
bio_for_each_folio_all(fi, bio)
folio_end_read(fi.folio, bio->bi_status == 0);
if (bio->bi_private)
- mempool_free(bio->bi_private, bio_post_read_ctx_pool);
+ mempool_free(bio->bi_private, ext4_verity_work_pool);
bio_put(bio);
}
static void verity_work(struct work_struct *work)
{
- struct bio_post_read_ctx *ctx =
- container_of(work, struct bio_post_read_ctx, work);
+ struct ext4_verity_work *ctx =
+ container_of(work, struct ext4_verity_work, work);
struct bio *bio = ctx->bio;
struct fsverity_info *vi = ctx->vi;
/*
- * Free the bio_post_read_ctx right away, since it's no longer needed.
+ * Free the ext4_verity_work right away, since it's no longer needed.
* This relieves the pressure on the mempool as much as possible.
*/
- mempool_free(ctx, bio_post_read_ctx_pool);
+ mempool_free(ctx, ext4_verity_work_pool);
bio->bi_private = NULL;
fsverity_verify_bio(vi, bio);
__read_end_io(bio);
}
-static bool bio_post_read_required(struct bio *bio)
-{
- return IS_ENABLED(CONFIG_FS_VERITY) && bio->bi_private &&
- !bio->bi_status;
-}
-
/*
* I/O completion handler for multipage BIOs.
*
* The mpage code never puts partial pages into a BIO (except for end-of-file).
* If a page does not map to a contiguous run of blocks then it simply falls
@@ -106,28 +100,28 @@ static bool bio_post_read_required(struct bio *bio)
* status of that page is hard. See end_buffer_async_read() for the details.
* There is no point in duplicating all that complexity.
*/
static void mpage_end_io(struct bio *bio)
{
- if (bio_post_read_required(bio)) {
- struct bio_post_read_ctx *ctx = bio->bi_private;
+ if (IS_ENABLED(CONFIG_FS_VERITY) && bio->bi_private &&
+ !bio->bi_status) {
+ struct ext4_verity_work *ctx = bio->bi_private;
INIT_WORK(&ctx->work, verity_work);
fsverity_enqueue_verify_work(&ctx->work);
return;
}
__read_end_io(bio);
}
-static void ext4_set_bio_post_read_ctx(struct bio *bio,
- const struct inode *inode,
- struct fsverity_info *vi)
+static void ext4_set_verity_work(struct bio *bio, const struct inode *inode,
+ struct fsverity_info *vi)
{
if (vi) {
/* Due to the mempool, this never fails. */
- struct bio_post_read_ctx *ctx =
- mempool_alloc(bio_post_read_ctx_pool, GFP_NOFS);
+ struct ext4_verity_work *ctx =
+ mempool_alloc(ext4_verity_work_pool, GFP_NOFS);
ctx->bio = bio;
ctx->vi = vi;
bio->bi_private = ctx;
}
@@ -287,11 +281,11 @@ static int ext4_mpage_readpages(struct inode *inode, struct fsverity_info *vi,
* __GFP_DIRECT_RECLAIM is set, see bio_alloc_bioset().
*/
bio = bio_alloc(bdev, bio_max_segs(nr_pages),
REQ_OP_READ, GFP_KERNEL);
fscrypt_set_bio_crypt_ctx(bio, inode, pos, GFP_KERNEL);
- ext4_set_bio_post_read_ctx(bio, inode, vi);
+ ext4_set_verity_work(bio, inode, vi);
bio->bi_iter.bi_sector = first_block << (blkbits - 9);
bio->bi_end_io = mpage_end_io;
if (rac)
bio->bi_opf |= REQ_RAHEAD;
}
@@ -361,29 +355,33 @@ void ext4_readahead(struct readahead_control *rac)
fsverity_readahead(vi, readahead_index(rac),
readahead_count(rac));
ext4_mpage_readpages(inode, vi, rac, NULL);
}
-int __init ext4_init_post_read_processing(void)
+int __init ext4_init_verity_caches(void)
{
- bio_post_read_ctx_cache = KMEM_CACHE(bio_post_read_ctx, SLAB_RECLAIM_ACCOUNT);
+ if (!IS_ENABLED(CONFIG_FS_VERITY))
+ return 0;
+ ext4_verity_work_cache =
+ KMEM_CACHE(ext4_verity_work, SLAB_RECLAIM_ACCOUNT);
- if (!bio_post_read_ctx_cache)
+ if (!ext4_verity_work_cache)
goto fail;
- bio_post_read_ctx_pool =
- mempool_create_slab_pool(NUM_PREALLOC_POST_READ_CTXS,
- bio_post_read_ctx_cache);
- if (!bio_post_read_ctx_pool)
+ ext4_verity_work_pool = mempool_create_slab_pool(
+ NUM_VERITY_WORKS, ext4_verity_work_cache);
+ if (!ext4_verity_work_pool)
goto fail_free_cache;
return 0;
fail_free_cache:
- kmem_cache_destroy(bio_post_read_ctx_cache);
+ kmem_cache_destroy(ext4_verity_work_cache);
fail:
return -ENOMEM;
}
-void ext4_exit_post_read_processing(void)
+void ext4_exit_verity_caches(void)
{
- mempool_destroy(bio_post_read_ctx_pool);
- kmem_cache_destroy(bio_post_read_ctx_cache);
+ if (!IS_ENABLED(CONFIG_FS_VERITY))
+ return;
+ mempool_destroy(ext4_verity_work_pool);
+ kmem_cache_destroy(ext4_verity_work_cache);
}
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 245f67d10ded..cb9ca0dc4664 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -7529,11 +7529,11 @@ static int __init ext4_init_fs(void)
err = ext4_init_pending();
if (err)
goto out7;
- err = ext4_init_post_read_processing();
+ err = ext4_init_verity_caches();
if (err)
goto out6;
err = ext4_init_pageio();
if (err)
@@ -7578,11 +7578,11 @@ static int __init ext4_init_fs(void)
out3:
ext4_exit_system_zone();
out4:
ext4_exit_pageio();
out5:
- ext4_exit_post_read_processing();
+ ext4_exit_verity_caches();
out6:
ext4_exit_pending();
out7:
ext4_exit_es();
@@ -7599,11 +7599,11 @@ static void __exit ext4_exit_fs(void)
destroy_inodecache();
ext4_exit_mballoc();
ext4_exit_sysfs();
ext4_exit_system_zone();
ext4_exit_pageio();
- ext4_exit_post_read_processing();
+ ext4_exit_verity_caches();
ext4_exit_es();
ext4_exit_pending();
}
MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others");
--
2.54.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [f2fs-dev] [PATCH 08/16] ext4: Further de-generalize the bio postprocessing code
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
0 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers via Linux-f2fs-devel @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: Ritesh Harjani, Theodore Ts'o, Zhang Yi, linux-f2fs-devel,
linux-block, Andreas Dilger, Ojaswin Mujoo, Baokun Li,
Jaegeuk Kim, linux-fsdevel, Jan Kara, linux-ext4,
Christoph Hellwig, Eric Biggers
Since the bio postprocessing code in fs/ext4/readpage.c is now used only
for fsverity, rename things accordingly. Also don't create the caches
at all when !CONFIG_FS_VERITY.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
fs/ext4/ext4.h | 4 +--
fs/ext4/readpage.c | 66 ++++++++++++++++++++++------------------------
fs/ext4/super.c | 6 ++---
3 files changed, 37 insertions(+), 39 deletions(-)
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 920a8ec1b948..af6cf0bbc5e2 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -3827,12 +3827,12 @@ static inline void ext4_set_de_type(struct super_block *sb,
}
/* readpages.c */
int ext4_read_folio(struct file *file, struct folio *folio);
void ext4_readahead(struct readahead_control *rac);
-extern int __init ext4_init_post_read_processing(void);
-extern void ext4_exit_post_read_processing(void);
+extern int __init ext4_init_verity_caches(void);
+extern void ext4_exit_verity_caches(void);
/* symlink.c */
extern const struct inode_operations ext4_encrypted_symlink_inode_operations;
extern const struct inode_operations ext4_symlink_inode_operations;
extern const struct inode_operations ext4_fast_symlink_inode_operations;
diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c
index 8af183798a33..322226290e65 100644
--- a/fs/ext4/readpage.c
+++ b/fs/ext4/readpage.c
@@ -45,16 +45,16 @@
#include <linux/backing-dev.h>
#include "ext4.h"
#include <trace/events/ext4.h>
-#define NUM_PREALLOC_POST_READ_CTXS 128
+#define NUM_VERITY_WORKS 128
-static struct kmem_cache *bio_post_read_ctx_cache;
-static mempool_t *bio_post_read_ctx_pool;
+static struct kmem_cache *ext4_verity_work_cache;
+static mempool_t *ext4_verity_work_pool;
-struct bio_post_read_ctx {
+struct ext4_verity_work {
struct bio *bio;
struct fsverity_info *vi;
struct work_struct work;
};
@@ -63,39 +63,33 @@ static void __read_end_io(struct bio *bio)
struct folio_iter fi;
bio_for_each_folio_all(fi, bio)
folio_end_read(fi.folio, bio->bi_status == 0);
if (bio->bi_private)
- mempool_free(bio->bi_private, bio_post_read_ctx_pool);
+ mempool_free(bio->bi_private, ext4_verity_work_pool);
bio_put(bio);
}
static void verity_work(struct work_struct *work)
{
- struct bio_post_read_ctx *ctx =
- container_of(work, struct bio_post_read_ctx, work);
+ struct ext4_verity_work *ctx =
+ container_of(work, struct ext4_verity_work, work);
struct bio *bio = ctx->bio;
struct fsverity_info *vi = ctx->vi;
/*
- * Free the bio_post_read_ctx right away, since it's no longer needed.
+ * Free the ext4_verity_work right away, since it's no longer needed.
* This relieves the pressure on the mempool as much as possible.
*/
- mempool_free(ctx, bio_post_read_ctx_pool);
+ mempool_free(ctx, ext4_verity_work_pool);
bio->bi_private = NULL;
fsverity_verify_bio(vi, bio);
__read_end_io(bio);
}
-static bool bio_post_read_required(struct bio *bio)
-{
- return IS_ENABLED(CONFIG_FS_VERITY) && bio->bi_private &&
- !bio->bi_status;
-}
-
/*
* I/O completion handler for multipage BIOs.
*
* The mpage code never puts partial pages into a BIO (except for end-of-file).
* If a page does not map to a contiguous run of blocks then it simply falls
@@ -106,28 +100,28 @@ static bool bio_post_read_required(struct bio *bio)
* status of that page is hard. See end_buffer_async_read() for the details.
* There is no point in duplicating all that complexity.
*/
static void mpage_end_io(struct bio *bio)
{
- if (bio_post_read_required(bio)) {
- struct bio_post_read_ctx *ctx = bio->bi_private;
+ if (IS_ENABLED(CONFIG_FS_VERITY) && bio->bi_private &&
+ !bio->bi_status) {
+ struct ext4_verity_work *ctx = bio->bi_private;
INIT_WORK(&ctx->work, verity_work);
fsverity_enqueue_verify_work(&ctx->work);
return;
}
__read_end_io(bio);
}
-static void ext4_set_bio_post_read_ctx(struct bio *bio,
- const struct inode *inode,
- struct fsverity_info *vi)
+static void ext4_set_verity_work(struct bio *bio, const struct inode *inode,
+ struct fsverity_info *vi)
{
if (vi) {
/* Due to the mempool, this never fails. */
- struct bio_post_read_ctx *ctx =
- mempool_alloc(bio_post_read_ctx_pool, GFP_NOFS);
+ struct ext4_verity_work *ctx =
+ mempool_alloc(ext4_verity_work_pool, GFP_NOFS);
ctx->bio = bio;
ctx->vi = vi;
bio->bi_private = ctx;
}
@@ -287,11 +281,11 @@ static int ext4_mpage_readpages(struct inode *inode, struct fsverity_info *vi,
* __GFP_DIRECT_RECLAIM is set, see bio_alloc_bioset().
*/
bio = bio_alloc(bdev, bio_max_segs(nr_pages),
REQ_OP_READ, GFP_KERNEL);
fscrypt_set_bio_crypt_ctx(bio, inode, pos, GFP_KERNEL);
- ext4_set_bio_post_read_ctx(bio, inode, vi);
+ ext4_set_verity_work(bio, inode, vi);
bio->bi_iter.bi_sector = first_block << (blkbits - 9);
bio->bi_end_io = mpage_end_io;
if (rac)
bio->bi_opf |= REQ_RAHEAD;
}
@@ -361,29 +355,33 @@ void ext4_readahead(struct readahead_control *rac)
fsverity_readahead(vi, readahead_index(rac),
readahead_count(rac));
ext4_mpage_readpages(inode, vi, rac, NULL);
}
-int __init ext4_init_post_read_processing(void)
+int __init ext4_init_verity_caches(void)
{
- bio_post_read_ctx_cache = KMEM_CACHE(bio_post_read_ctx, SLAB_RECLAIM_ACCOUNT);
+ if (!IS_ENABLED(CONFIG_FS_VERITY))
+ return 0;
+ ext4_verity_work_cache =
+ KMEM_CACHE(ext4_verity_work, SLAB_RECLAIM_ACCOUNT);
- if (!bio_post_read_ctx_cache)
+ if (!ext4_verity_work_cache)
goto fail;
- bio_post_read_ctx_pool =
- mempool_create_slab_pool(NUM_PREALLOC_POST_READ_CTXS,
- bio_post_read_ctx_cache);
- if (!bio_post_read_ctx_pool)
+ ext4_verity_work_pool = mempool_create_slab_pool(
+ NUM_VERITY_WORKS, ext4_verity_work_cache);
+ if (!ext4_verity_work_pool)
goto fail_free_cache;
return 0;
fail_free_cache:
- kmem_cache_destroy(bio_post_read_ctx_cache);
+ kmem_cache_destroy(ext4_verity_work_cache);
fail:
return -ENOMEM;
}
-void ext4_exit_post_read_processing(void)
+void ext4_exit_verity_caches(void)
{
- mempool_destroy(bio_post_read_ctx_pool);
- kmem_cache_destroy(bio_post_read_ctx_cache);
+ if (!IS_ENABLED(CONFIG_FS_VERITY))
+ return;
+ mempool_destroy(ext4_verity_work_pool);
+ kmem_cache_destroy(ext4_verity_work_cache);
}
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 245f67d10ded..cb9ca0dc4664 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -7529,11 +7529,11 @@ static int __init ext4_init_fs(void)
err = ext4_init_pending();
if (err)
goto out7;
- err = ext4_init_post_read_processing();
+ err = ext4_init_verity_caches();
if (err)
goto out6;
err = ext4_init_pageio();
if (err)
@@ -7578,11 +7578,11 @@ static int __init ext4_init_fs(void)
out3:
ext4_exit_system_zone();
out4:
ext4_exit_pageio();
out5:
- ext4_exit_post_read_processing();
+ ext4_exit_verity_caches();
out6:
ext4_exit_pending();
out7:
ext4_exit_es();
@@ -7599,11 +7599,11 @@ static void __exit ext4_exit_fs(void)
destroy_inodecache();
ext4_exit_mballoc();
ext4_exit_sysfs();
ext4_exit_system_zone();
ext4_exit_pageio();
- ext4_exit_post_read_processing();
+ ext4_exit_verity_caches();
ext4_exit_es();
ext4_exit_pending();
}
MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others");
--
2.54.0
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 09/16] f2fs: Remove fs-layer file contents en/decryption code
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
-1 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: linux-fsdevel, linux-ext4, linux-f2fs-devel, linux-block,
Christoph Hellwig, Theodore Ts'o, Andreas Dilger, Baokun Li,
Jan Kara, Ojaswin Mujoo, Ritesh Harjani, Zhang Yi, Jaegeuk Kim,
Chao Yu, Eric Biggers
Now that fscrypt's file contents en/decryption is always implemented
using blk-crypto when the filesystem is block-based, the fs-layer
en/decryption code in f2fs is unused code. Remove it.
Note that the struct f2fs_io_info field encrypted_page is kept because
it is still used by the garbage collection path to relocate encrypted
blocks using raw meta pages from META_MAPPING.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
fs/f2fs/compress.c | 28 ++------------
fs/f2fs/data.c | 93 +++++-----------------------------------------
fs/f2fs/f2fs.h | 2 -
fs/f2fs/segment.c | 2 -
fs/f2fs/super.c | 1 -
5 files changed, 12 insertions(+), 114 deletions(-)
diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
index 881e76158b96..e0ad9ba315b4 100644
--- a/fs/f2fs/compress.c
+++ b/fs/f2fs/compress.c
@@ -1282,12 +1282,10 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
.page = NULL,
.encrypted_page = NULL,
.compressed_page = NULL,
.io_type = io_type,
.io_wbc = wbc,
- .encrypted = fscrypt_inode_uses_fs_layer_crypto(cc->inode) ?
- 1 : 0,
};
struct folio *folio;
struct dnode_of_data dn;
struct node_info ni;
struct compress_io_ctx *cic;
@@ -1357,18 +1355,10 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
fio.old_blkaddr = data_blkaddr(dn.inode, dn.node_folio,
dn.ofs_in_node + i + 1);
/* wait for GCed page writeback via META_MAPPING */
f2fs_wait_on_block_writeback(inode, fio.old_blkaddr);
-
- if (fio.encrypted) {
- fio.page = cc->rpages[i + 1];
- err = f2fs_encrypt_one_page(&fio);
- if (err)
- goto out_destroy_crypt;
- cc->cpages[i] = fio.encrypted_page;
- }
}
set_cluster_writeback(cc);
for (i = 0; i < cc->cluster_size; i++)
@@ -1402,25 +1392,19 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
goto unlock_continue;
}
f2fs_bug_on(fio.sbi, blkaddr == NULL_ADDR);
- if (fio.encrypted)
- fio.encrypted_page = cc->cpages[i - 1];
- else
- fio.compressed_page = cc->cpages[i - 1];
+ fio.compressed_page = cc->cpages[i - 1];
cc->cpages[i - 1] = NULL;
fio.submitted = 0;
f2fs_outplace_write_data(&dn, &fio);
if (unlikely(!fio.submitted)) {
cancel_cluster_writeback(cc, cic, i);
-
- /* To call fscrypt_finalize_bounce_page */
- i = cc->valid_nr_cpages;
*submitted = 0;
- goto out_destroy_crypt;
+ goto out_free_page_array;
}
(*submitted)++;
unlock_continue:
inode_dec_dirty_pages(cc->inode);
folio_unlock(fio.folio);
@@ -1448,18 +1432,12 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
page_array_free(sbi, cc->cpages, cc->nr_cpages);
cc->cpages = NULL;
f2fs_destroy_compress_ctx(cc, false);
return 0;
-out_destroy_crypt:
+out_free_page_array:
page_array_free(sbi, cic->rpages, cc->cluster_size);
-
- for (--i; i >= 0; i--) {
- if (!cc->cpages[i])
- continue;
- fscrypt_finalize_bounce_page(&cc->cpages[i]);
- }
out_put_cic:
kmem_cache_free(cic_entry_slab, cic);
out_put_dnode:
f2fs_put_dnode(&dn);
out_unlock_op:
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 8d4f1e75dee3..315bfe40da87 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -57,13 +57,10 @@ bool f2fs_is_cp_guaranteed(const struct folio *folio)
{
struct address_space *mapping = folio->mapping;
struct inode *inode;
struct f2fs_sb_info *sbi;
- if (fscrypt_is_bounce_folio(folio))
- return folio_test_f2fs_gcing(fscrypt_pagecache_folio(folio));
-
inode = mapping->host;
sbi = F2FS_I_SB(inode);
if (inode->i_ino == F2FS_META_INO(sbi) ||
inode->i_ino == F2FS_NODE_INO(sbi) ||
@@ -93,15 +90,10 @@ static enum count_type __read_io_type(struct folio *folio)
return F2FS_RD_DATA;
}
/* postprocessing steps for read bios */
enum bio_post_read_step {
-#ifdef CONFIG_FS_ENCRYPTION
- STEP_DECRYPT = BIT(0),
-#else
- STEP_DECRYPT = 0, /* compile out the decryption-related code */
-#endif
#ifdef CONFIG_F2FS_FS_COMPRESSION
STEP_DECOMPRESS = BIT(1),
#else
STEP_DECOMPRESS = 0, /* compile out the decompression-related code */
#endif
@@ -293,15 +285,10 @@ static void f2fs_post_read_work(struct work_struct *work)
{
struct bio_post_read_ctx *ctx =
container_of(work, struct bio_post_read_ctx, work);
struct bio *bio = ctx->bio;
- if ((ctx->enabled_steps & STEP_DECRYPT) && !fscrypt_decrypt_bio(bio)) {
- f2fs_finish_read_bio(bio, true);
- return;
- }
-
if (ctx->enabled_steps & STEP_DECOMPRESS)
f2fs_handle_step_decompress(ctx, true);
f2fs_verify_and_finish_bio(bio, true);
}
@@ -321,22 +308,15 @@ static void f2fs_read_end_io(struct bio *bio)
if (bio->bi_status != BLK_STS_OK) {
f2fs_finish_read_bio(bio, intask);
return;
}
- if (ctx) {
- unsigned int enabled_steps = ctx->enabled_steps &
- (STEP_DECRYPT | STEP_DECOMPRESS);
-
- /*
- * If we have only decompression step between decompression and
- * decrypt, we don't need post processing for this.
- */
- if (enabled_steps == STEP_DECOMPRESS &&
- !f2fs_low_mem_mode(sbi)) {
+ if (ctx && (ctx->enabled_steps & STEP_DECOMPRESS)) {
+ if (!f2fs_low_mem_mode(sbi)) {
+ /* Decompress inline. */
f2fs_handle_step_decompress(ctx, intask);
- } else if (enabled_steps) {
+ } else {
INIT_WORK(&ctx->work, f2fs_post_read_work);
queue_work(ctx->sbi->post_read_wq, &ctx->work);
return;
}
}
@@ -357,17 +337,10 @@ static void f2fs_write_end_io(struct bio *bio)
bio_for_each_folio_all(fi, bio) {
struct folio *folio = fi.folio;
enum count_type type;
- if (fscrypt_is_bounce_folio(folio)) {
- struct folio *io_folio = folio;
-
- folio = fscrypt_pagecache_folio(io_folio);
- fscrypt_free_bounce_page(&io_folio->page);
- }
-
#ifdef CONFIG_F2FS_FS_COMPRESSION
if (f2fs_is_compressed_page(folio)) {
f2fs_compress_write_end_io(bio, folio);
continue;
}
@@ -599,15 +572,10 @@ static bool __has_merged_page(struct bio *bio, struct inode *inode,
return true;
bio_for_each_folio_all(fi, bio) {
struct folio *target = fi.folio;
- if (fscrypt_is_bounce_folio(target)) {
- target = fscrypt_pagecache_folio(target);
- if (IS_ERR(target))
- continue;
- }
if (f2fs_is_compressed_page(target)) {
target = f2fs_compress_control_folio(target);
if (IS_ERR(target))
continue;
}
@@ -1117,13 +1085,10 @@ static struct bio *f2fs_grab_read_bio(struct inode *inode,
for_write ? GFP_NOIO : GFP_KERNEL, &f2fs_bioset);
bio->bi_iter.bi_sector = sector;
f2fs_set_bio_crypt_ctx(bio, inode, first_idx, NULL, GFP_NOFS);
bio->bi_end_io = f2fs_read_end_io;
- if (fscrypt_inode_uses_fs_layer_crypto(inode))
- post_read_steps |= STEP_DECRYPT;
-
if (vi)
post_read_steps |= STEP_VERITY;
/*
* STEP_DECOMPRESS is handled specially, since a compressed file might
@@ -2808,39 +2773,10 @@ static void f2fs_readahead(struct readahead_control *rac)
fsverity_readahead(vi, readahead_index(rac),
readahead_count(rac));
f2fs_mpage_readpages(inode, vi, rac, NULL);
}
-int f2fs_encrypt_one_page(struct f2fs_io_info *fio)
-{
- struct inode *inode = fio_inode(fio);
- struct folio *mfolio;
- struct page *page;
-
- if (!f2fs_encrypted_file(inode))
- return 0;
-
- page = fio->compressed_page ? fio->compressed_page : fio->page;
-
- if (fscrypt_inode_uses_inline_crypto(inode))
- return 0;
-
- fio->encrypted_page = fscrypt_encrypt_pagecache_blocks(page_folio(page),
- PAGE_SIZE, 0, GFP_NOFS);
- if (IS_ERR(fio->encrypted_page))
- return PTR_ERR(fio->encrypted_page);
-
- mfolio = filemap_lock_folio(META_MAPPING(fio->sbi), fio->old_blkaddr);
- if (!IS_ERR(mfolio)) {
- if (folio_test_uptodate(mfolio))
- memcpy(folio_address(mfolio),
- page_address(fio->encrypted_page), PAGE_SIZE);
- f2fs_folio_put(mfolio, true);
- }
- return 0;
-}
-
static inline bool check_inplace_update_policy(struct inode *inode,
struct f2fs_io_info *fio)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
@@ -3009,26 +2945,19 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
* it had better in-place writes for updated data.
*/
if (ipu_force ||
(__is_valid_data_blkaddr(fio->old_blkaddr) &&
need_inplace_update(fio))) {
- err = f2fs_encrypt_one_page(fio);
- if (err)
- goto out_writepage;
-
folio_start_writeback(folio);
f2fs_put_dnode(&dn);
if (fio->need_lock == LOCK_REQ)
f2fs_unlock_op(fio->sbi, &lc);
err = f2fs_inplace_write_data(fio);
- if (err) {
- if (fscrypt_inode_uses_fs_layer_crypto(inode))
- fscrypt_finalize_bounce_page(&fio->encrypted_page);
+ if (err)
folio_end_writeback(folio);
- } else {
+ else
set_inode_flag(inode, FI_UPDATE_WRITE);
- }
trace_f2fs_do_write_data_page(folio, IPU);
return err;
}
if (fio->need_lock == LOCK_RETRY) {
@@ -3043,14 +2972,10 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
if (err)
goto out_writepage;
fio->version = ni.version;
- err = f2fs_encrypt_one_page(fio);
- if (err)
- goto out_writepage;
-
folio_start_writeback(folio);
if (fio->compr_blocks && fio->old_blkaddr == COMPRESS_ADDR)
f2fs_i_compr_blocks_update(inode, fio->compr_blocks - 1, false);
@@ -4547,13 +4472,13 @@ static int f2fs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
return err;
iomap->offset = F2FS_BLK_TO_BYTES(map.m_lblk);
/*
- * 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.
+ * 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);
/*
* We should never see delalloc or compressed extents here based on
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 91f506e7c9cf..746e678ceb1a 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -1353,11 +1353,10 @@ struct f2fs_io_info {
unsigned int need_lock:8; /* indicate we need to lock cp_rwsem */
unsigned int version:8; /* version of the node */
unsigned int submitted:1; /* indicate IO submission */
unsigned int in_list:1; /* indicate fio is in io_list */
unsigned int is_por:1; /* indicate IO is from recovery or not */
- unsigned int encrypted:1; /* indicate file is encrypted */
unsigned int meta_gc:1; /* require meta inode GC */
enum iostat_type io_type; /* io type */
struct writeback_control *io_wbc; /* writeback control */
struct bio **bio; /* bio for ipu */
sector_t *last_block; /* last block number in bio */
@@ -4176,11 +4175,10 @@ struct folio *f2fs_get_new_data_folio(struct inode *inode,
struct folio *ifolio, pgoff_t index, bool new_i_size);
int f2fs_do_write_data_page(struct f2fs_io_info *fio);
int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, int flag);
int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
u64 start, u64 len);
-int f2fs_encrypt_one_page(struct f2fs_io_info *fio);
bool f2fs_should_update_inplace(struct inode *inode, struct f2fs_io_info *fio);
bool f2fs_should_update_outplace(struct inode *inode, struct f2fs_io_info *fio);
int f2fs_write_single_data_page(struct folio *folio, int *submitted,
struct bio **bio, sector_t *last_block,
struct writeback_control *wbc,
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index 788f8b050249..e45eb0ff961d 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -3985,12 +3985,10 @@ static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio)
if (unlikely(err)) {
f2fs_err_ratelimited(fio->sbi,
"%s Failed to allocate data block, ino:%u, index:%lu, type:%d, old_blkaddr:0x%x, new_blkaddr:0x%x, err:%d",
__func__, fio->ino, folio->index, type,
fio->old_blkaddr, fio->new_blkaddr, err);
- if (fscrypt_inode_uses_fs_layer_crypto(folio->mapping->host))
- fscrypt_finalize_bounce_page(&fio->encrypted_page);
folio_end_writeback(folio);
if (f2fs_in_warm_node_list(folio))
f2fs_del_fsync_node_entry(fio->sbi, folio);
f2fs_bug_on(fio->sbi, !is_set_ckpt_flags(fio->sbi,
CP_ERROR_FLAG));
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index f3f6768f8cca..fd9d3ea4c058 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -3753,11 +3753,10 @@ static struct block_device **f2fs_get_devices(struct super_block *sb,
static const struct fscrypt_operations f2fs_cryptops = {
.inode_info_offs = (int)offsetof(struct f2fs_inode_info, i_crypt_info) -
(int)offsetof(struct f2fs_inode_info, vfs_inode),
.is_block_based = 1,
- .needs_bounce_pages = 1,
.has_32bit_inodes = 1,
.supports_subblock_data_units = 1,
.legacy_key_prefix = "f2fs:",
.get_context = f2fs_get_context,
.set_context = f2fs_set_context,
--
2.54.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [f2fs-dev] [PATCH 09/16] f2fs: Remove fs-layer file contents en/decryption code
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
0 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers via Linux-f2fs-devel @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: Ritesh Harjani, Theodore Ts'o, Zhang Yi, linux-f2fs-devel,
linux-block, Andreas Dilger, Ojaswin Mujoo, Baokun Li,
Jaegeuk Kim, linux-fsdevel, Jan Kara, linux-ext4,
Christoph Hellwig, Eric Biggers
Now that fscrypt's file contents en/decryption is always implemented
using blk-crypto when the filesystem is block-based, the fs-layer
en/decryption code in f2fs is unused code. Remove it.
Note that the struct f2fs_io_info field encrypted_page is kept because
it is still used by the garbage collection path to relocate encrypted
blocks using raw meta pages from META_MAPPING.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
fs/f2fs/compress.c | 28 ++------------
fs/f2fs/data.c | 93 +++++-----------------------------------------
fs/f2fs/f2fs.h | 2 -
fs/f2fs/segment.c | 2 -
fs/f2fs/super.c | 1 -
5 files changed, 12 insertions(+), 114 deletions(-)
diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
index 881e76158b96..e0ad9ba315b4 100644
--- a/fs/f2fs/compress.c
+++ b/fs/f2fs/compress.c
@@ -1282,12 +1282,10 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
.page = NULL,
.encrypted_page = NULL,
.compressed_page = NULL,
.io_type = io_type,
.io_wbc = wbc,
- .encrypted = fscrypt_inode_uses_fs_layer_crypto(cc->inode) ?
- 1 : 0,
};
struct folio *folio;
struct dnode_of_data dn;
struct node_info ni;
struct compress_io_ctx *cic;
@@ -1357,18 +1355,10 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
fio.old_blkaddr = data_blkaddr(dn.inode, dn.node_folio,
dn.ofs_in_node + i + 1);
/* wait for GCed page writeback via META_MAPPING */
f2fs_wait_on_block_writeback(inode, fio.old_blkaddr);
-
- if (fio.encrypted) {
- fio.page = cc->rpages[i + 1];
- err = f2fs_encrypt_one_page(&fio);
- if (err)
- goto out_destroy_crypt;
- cc->cpages[i] = fio.encrypted_page;
- }
}
set_cluster_writeback(cc);
for (i = 0; i < cc->cluster_size; i++)
@@ -1402,25 +1392,19 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
goto unlock_continue;
}
f2fs_bug_on(fio.sbi, blkaddr == NULL_ADDR);
- if (fio.encrypted)
- fio.encrypted_page = cc->cpages[i - 1];
- else
- fio.compressed_page = cc->cpages[i - 1];
+ fio.compressed_page = cc->cpages[i - 1];
cc->cpages[i - 1] = NULL;
fio.submitted = 0;
f2fs_outplace_write_data(&dn, &fio);
if (unlikely(!fio.submitted)) {
cancel_cluster_writeback(cc, cic, i);
-
- /* To call fscrypt_finalize_bounce_page */
- i = cc->valid_nr_cpages;
*submitted = 0;
- goto out_destroy_crypt;
+ goto out_free_page_array;
}
(*submitted)++;
unlock_continue:
inode_dec_dirty_pages(cc->inode);
folio_unlock(fio.folio);
@@ -1448,18 +1432,12 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
page_array_free(sbi, cc->cpages, cc->nr_cpages);
cc->cpages = NULL;
f2fs_destroy_compress_ctx(cc, false);
return 0;
-out_destroy_crypt:
+out_free_page_array:
page_array_free(sbi, cic->rpages, cc->cluster_size);
-
- for (--i; i >= 0; i--) {
- if (!cc->cpages[i])
- continue;
- fscrypt_finalize_bounce_page(&cc->cpages[i]);
- }
out_put_cic:
kmem_cache_free(cic_entry_slab, cic);
out_put_dnode:
f2fs_put_dnode(&dn);
out_unlock_op:
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 8d4f1e75dee3..315bfe40da87 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -57,13 +57,10 @@ bool f2fs_is_cp_guaranteed(const struct folio *folio)
{
struct address_space *mapping = folio->mapping;
struct inode *inode;
struct f2fs_sb_info *sbi;
- if (fscrypt_is_bounce_folio(folio))
- return folio_test_f2fs_gcing(fscrypt_pagecache_folio(folio));
-
inode = mapping->host;
sbi = F2FS_I_SB(inode);
if (inode->i_ino == F2FS_META_INO(sbi) ||
inode->i_ino == F2FS_NODE_INO(sbi) ||
@@ -93,15 +90,10 @@ static enum count_type __read_io_type(struct folio *folio)
return F2FS_RD_DATA;
}
/* postprocessing steps for read bios */
enum bio_post_read_step {
-#ifdef CONFIG_FS_ENCRYPTION
- STEP_DECRYPT = BIT(0),
-#else
- STEP_DECRYPT = 0, /* compile out the decryption-related code */
-#endif
#ifdef CONFIG_F2FS_FS_COMPRESSION
STEP_DECOMPRESS = BIT(1),
#else
STEP_DECOMPRESS = 0, /* compile out the decompression-related code */
#endif
@@ -293,15 +285,10 @@ static void f2fs_post_read_work(struct work_struct *work)
{
struct bio_post_read_ctx *ctx =
container_of(work, struct bio_post_read_ctx, work);
struct bio *bio = ctx->bio;
- if ((ctx->enabled_steps & STEP_DECRYPT) && !fscrypt_decrypt_bio(bio)) {
- f2fs_finish_read_bio(bio, true);
- return;
- }
-
if (ctx->enabled_steps & STEP_DECOMPRESS)
f2fs_handle_step_decompress(ctx, true);
f2fs_verify_and_finish_bio(bio, true);
}
@@ -321,22 +308,15 @@ static void f2fs_read_end_io(struct bio *bio)
if (bio->bi_status != BLK_STS_OK) {
f2fs_finish_read_bio(bio, intask);
return;
}
- if (ctx) {
- unsigned int enabled_steps = ctx->enabled_steps &
- (STEP_DECRYPT | STEP_DECOMPRESS);
-
- /*
- * If we have only decompression step between decompression and
- * decrypt, we don't need post processing for this.
- */
- if (enabled_steps == STEP_DECOMPRESS &&
- !f2fs_low_mem_mode(sbi)) {
+ if (ctx && (ctx->enabled_steps & STEP_DECOMPRESS)) {
+ if (!f2fs_low_mem_mode(sbi)) {
+ /* Decompress inline. */
f2fs_handle_step_decompress(ctx, intask);
- } else if (enabled_steps) {
+ } else {
INIT_WORK(&ctx->work, f2fs_post_read_work);
queue_work(ctx->sbi->post_read_wq, &ctx->work);
return;
}
}
@@ -357,17 +337,10 @@ static void f2fs_write_end_io(struct bio *bio)
bio_for_each_folio_all(fi, bio) {
struct folio *folio = fi.folio;
enum count_type type;
- if (fscrypt_is_bounce_folio(folio)) {
- struct folio *io_folio = folio;
-
- folio = fscrypt_pagecache_folio(io_folio);
- fscrypt_free_bounce_page(&io_folio->page);
- }
-
#ifdef CONFIG_F2FS_FS_COMPRESSION
if (f2fs_is_compressed_page(folio)) {
f2fs_compress_write_end_io(bio, folio);
continue;
}
@@ -599,15 +572,10 @@ static bool __has_merged_page(struct bio *bio, struct inode *inode,
return true;
bio_for_each_folio_all(fi, bio) {
struct folio *target = fi.folio;
- if (fscrypt_is_bounce_folio(target)) {
- target = fscrypt_pagecache_folio(target);
- if (IS_ERR(target))
- continue;
- }
if (f2fs_is_compressed_page(target)) {
target = f2fs_compress_control_folio(target);
if (IS_ERR(target))
continue;
}
@@ -1117,13 +1085,10 @@ static struct bio *f2fs_grab_read_bio(struct inode *inode,
for_write ? GFP_NOIO : GFP_KERNEL, &f2fs_bioset);
bio->bi_iter.bi_sector = sector;
f2fs_set_bio_crypt_ctx(bio, inode, first_idx, NULL, GFP_NOFS);
bio->bi_end_io = f2fs_read_end_io;
- if (fscrypt_inode_uses_fs_layer_crypto(inode))
- post_read_steps |= STEP_DECRYPT;
-
if (vi)
post_read_steps |= STEP_VERITY;
/*
* STEP_DECOMPRESS is handled specially, since a compressed file might
@@ -2808,39 +2773,10 @@ static void f2fs_readahead(struct readahead_control *rac)
fsverity_readahead(vi, readahead_index(rac),
readahead_count(rac));
f2fs_mpage_readpages(inode, vi, rac, NULL);
}
-int f2fs_encrypt_one_page(struct f2fs_io_info *fio)
-{
- struct inode *inode = fio_inode(fio);
- struct folio *mfolio;
- struct page *page;
-
- if (!f2fs_encrypted_file(inode))
- return 0;
-
- page = fio->compressed_page ? fio->compressed_page : fio->page;
-
- if (fscrypt_inode_uses_inline_crypto(inode))
- return 0;
-
- fio->encrypted_page = fscrypt_encrypt_pagecache_blocks(page_folio(page),
- PAGE_SIZE, 0, GFP_NOFS);
- if (IS_ERR(fio->encrypted_page))
- return PTR_ERR(fio->encrypted_page);
-
- mfolio = filemap_lock_folio(META_MAPPING(fio->sbi), fio->old_blkaddr);
- if (!IS_ERR(mfolio)) {
- if (folio_test_uptodate(mfolio))
- memcpy(folio_address(mfolio),
- page_address(fio->encrypted_page), PAGE_SIZE);
- f2fs_folio_put(mfolio, true);
- }
- return 0;
-}
-
static inline bool check_inplace_update_policy(struct inode *inode,
struct f2fs_io_info *fio)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
@@ -3009,26 +2945,19 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
* it had better in-place writes for updated data.
*/
if (ipu_force ||
(__is_valid_data_blkaddr(fio->old_blkaddr) &&
need_inplace_update(fio))) {
- err = f2fs_encrypt_one_page(fio);
- if (err)
- goto out_writepage;
-
folio_start_writeback(folio);
f2fs_put_dnode(&dn);
if (fio->need_lock == LOCK_REQ)
f2fs_unlock_op(fio->sbi, &lc);
err = f2fs_inplace_write_data(fio);
- if (err) {
- if (fscrypt_inode_uses_fs_layer_crypto(inode))
- fscrypt_finalize_bounce_page(&fio->encrypted_page);
+ if (err)
folio_end_writeback(folio);
- } else {
+ else
set_inode_flag(inode, FI_UPDATE_WRITE);
- }
trace_f2fs_do_write_data_page(folio, IPU);
return err;
}
if (fio->need_lock == LOCK_RETRY) {
@@ -3043,14 +2972,10 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
if (err)
goto out_writepage;
fio->version = ni.version;
- err = f2fs_encrypt_one_page(fio);
- if (err)
- goto out_writepage;
-
folio_start_writeback(folio);
if (fio->compr_blocks && fio->old_blkaddr == COMPRESS_ADDR)
f2fs_i_compr_blocks_update(inode, fio->compr_blocks - 1, false);
@@ -4547,13 +4472,13 @@ static int f2fs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
return err;
iomap->offset = F2FS_BLK_TO_BYTES(map.m_lblk);
/*
- * 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.
+ * 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);
/*
* We should never see delalloc or compressed extents here based on
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 91f506e7c9cf..746e678ceb1a 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -1353,11 +1353,10 @@ struct f2fs_io_info {
unsigned int need_lock:8; /* indicate we need to lock cp_rwsem */
unsigned int version:8; /* version of the node */
unsigned int submitted:1; /* indicate IO submission */
unsigned int in_list:1; /* indicate fio is in io_list */
unsigned int is_por:1; /* indicate IO is from recovery or not */
- unsigned int encrypted:1; /* indicate file is encrypted */
unsigned int meta_gc:1; /* require meta inode GC */
enum iostat_type io_type; /* io type */
struct writeback_control *io_wbc; /* writeback control */
struct bio **bio; /* bio for ipu */
sector_t *last_block; /* last block number in bio */
@@ -4176,11 +4175,10 @@ struct folio *f2fs_get_new_data_folio(struct inode *inode,
struct folio *ifolio, pgoff_t index, bool new_i_size);
int f2fs_do_write_data_page(struct f2fs_io_info *fio);
int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, int flag);
int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
u64 start, u64 len);
-int f2fs_encrypt_one_page(struct f2fs_io_info *fio);
bool f2fs_should_update_inplace(struct inode *inode, struct f2fs_io_info *fio);
bool f2fs_should_update_outplace(struct inode *inode, struct f2fs_io_info *fio);
int f2fs_write_single_data_page(struct folio *folio, int *submitted,
struct bio **bio, sector_t *last_block,
struct writeback_control *wbc,
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index 788f8b050249..e45eb0ff961d 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -3985,12 +3985,10 @@ static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio)
if (unlikely(err)) {
f2fs_err_ratelimited(fio->sbi,
"%s Failed to allocate data block, ino:%u, index:%lu, type:%d, old_blkaddr:0x%x, new_blkaddr:0x%x, err:%d",
__func__, fio->ino, folio->index, type,
fio->old_blkaddr, fio->new_blkaddr, err);
- if (fscrypt_inode_uses_fs_layer_crypto(folio->mapping->host))
- fscrypt_finalize_bounce_page(&fio->encrypted_page);
folio_end_writeback(folio);
if (f2fs_in_warm_node_list(folio))
f2fs_del_fsync_node_entry(fio->sbi, folio);
f2fs_bug_on(fio->sbi, !is_set_ckpt_flags(fio->sbi,
CP_ERROR_FLAG));
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index f3f6768f8cca..fd9d3ea4c058 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -3753,11 +3753,10 @@ static struct block_device **f2fs_get_devices(struct super_block *sb,
static const struct fscrypt_operations f2fs_cryptops = {
.inode_info_offs = (int)offsetof(struct f2fs_inode_info, i_crypt_info) -
(int)offsetof(struct f2fs_inode_info, vfs_inode),
.is_block_based = 1,
- .needs_bounce_pages = 1,
.has_32bit_inodes = 1,
.supports_subblock_data_units = 1,
.legacy_key_prefix = "f2fs:",
.get_context = f2fs_get_context,
.set_context = f2fs_set_context,
--
2.54.0
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 10/16] fs/buffer: Remove fs-layer decryption code
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
-1 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: linux-fsdevel, linux-ext4, linux-f2fs-devel, linux-block,
Christoph Hellwig, Theodore Ts'o, Andreas Dilger, Baokun Li,
Jan Kara, Ojaswin Mujoo, Ritesh Harjani, Zhang Yi, Jaegeuk Kim,
Chao Yu, Eric Biggers
Now that fscrypt's file contents en/decryption is always implemented
using blk-crypto when the filesystem is block-based, the fs-layer
decryption code in fs/buffer.c is unused code. Remove it.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
fs/buffer.c | 45 ++++++++-------------------------------------
1 file changed, 8 insertions(+), 37 deletions(-)
diff --git a/fs/buffer.c b/fs/buffer.c
index 9af5f061a1f8..21dd9596a941 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -334,82 +334,53 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
still_busy:
spin_unlock_irqrestore(&first->b_uptodate_lock, flags);
}
-struct postprocess_bh_ctx {
+struct verify_bh_ctx {
struct work_struct work;
struct buffer_head *bh;
struct fsverity_info *vi;
};
static void verify_bh(struct work_struct *work)
{
- struct postprocess_bh_ctx *ctx =
- container_of(work, struct postprocess_bh_ctx, work);
+ struct verify_bh_ctx *ctx =
+ container_of(work, struct verify_bh_ctx, work);
struct buffer_head *bh = ctx->bh;
bool valid;
valid = fsverity_verify_blocks(ctx->vi, bh->b_folio, bh->b_size,
bh_offset(bh));
end_buffer_async_read(bh, valid);
kfree(ctx);
}
-static void decrypt_bh(struct work_struct *work)
-{
- struct postprocess_bh_ctx *ctx =
- container_of(work, struct postprocess_bh_ctx, work);
- struct buffer_head *bh = ctx->bh;
- int err;
-
- err = fscrypt_decrypt_pagecache_blocks(bh->b_folio, bh->b_size,
- bh_offset(bh));
- if (err == 0 && ctx->vi) {
- /*
- * We use different work queues for decryption and for verity
- * because verity may require reading metadata pages that need
- * decryption, and we shouldn't recurse to the same workqueue.
- */
- INIT_WORK(&ctx->work, verify_bh);
- fsverity_enqueue_verify_work(&ctx->work);
- return;
- }
- end_buffer_async_read(bh, err == 0);
- kfree(ctx);
-}
-
/*
* I/O completion handler for block_read_full_folio() - folios
* which come unlocked at the end of I/O.
*/
static void bh_end_async_read(struct bio *bio)
{
struct buffer_head *bh;
bool uptodate = bio_endio_bh(bio, &bh);
struct inode *inode = bh->b_folio->mapping->host;
- bool decrypt = fscrypt_inode_uses_fs_layer_crypto(inode);
struct fsverity_info *vi = NULL;
/* needed by ext4 */
if (bh->b_folio->index < DIV_ROUND_UP(inode->i_size, PAGE_SIZE))
vi = fsverity_get_info(inode);
- /* Decrypt (with fscrypt) and/or verify (with fsverity) if needed. */
- if (uptodate && (decrypt || vi)) {
- struct postprocess_bh_ctx *ctx = kmalloc_obj(*ctx, GFP_ATOMIC);
+ /* Verify (with fsverity) if needed. */
+ if (vi && uptodate) {
+ struct verify_bh_ctx *ctx = kmalloc_obj(*ctx, GFP_ATOMIC);
if (ctx) {
ctx->bh = bh;
ctx->vi = vi;
- if (decrypt) {
- INIT_WORK(&ctx->work, decrypt_bh);
- fscrypt_enqueue_decrypt_work(&ctx->work);
- } else {
- INIT_WORK(&ctx->work, verify_bh);
- fsverity_enqueue_verify_work(&ctx->work);
- }
+ INIT_WORK(&ctx->work, verify_bh);
+ fsverity_enqueue_verify_work(&ctx->work);
return;
}
uptodate = false;
}
end_buffer_async_read(bh, uptodate);
--
2.54.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [f2fs-dev] [PATCH 10/16] fs/buffer: Remove fs-layer decryption code
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
0 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers via Linux-f2fs-devel @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: Ritesh Harjani, Theodore Ts'o, Zhang Yi, linux-f2fs-devel,
linux-block, Andreas Dilger, Ojaswin Mujoo, Baokun Li,
Jaegeuk Kim, linux-fsdevel, Jan Kara, linux-ext4,
Christoph Hellwig, Eric Biggers
Now that fscrypt's file contents en/decryption is always implemented
using blk-crypto when the filesystem is block-based, the fs-layer
decryption code in fs/buffer.c is unused code. Remove it.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
fs/buffer.c | 45 ++++++++-------------------------------------
1 file changed, 8 insertions(+), 37 deletions(-)
diff --git a/fs/buffer.c b/fs/buffer.c
index 9af5f061a1f8..21dd9596a941 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -334,82 +334,53 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
still_busy:
spin_unlock_irqrestore(&first->b_uptodate_lock, flags);
}
-struct postprocess_bh_ctx {
+struct verify_bh_ctx {
struct work_struct work;
struct buffer_head *bh;
struct fsverity_info *vi;
};
static void verify_bh(struct work_struct *work)
{
- struct postprocess_bh_ctx *ctx =
- container_of(work, struct postprocess_bh_ctx, work);
+ struct verify_bh_ctx *ctx =
+ container_of(work, struct verify_bh_ctx, work);
struct buffer_head *bh = ctx->bh;
bool valid;
valid = fsverity_verify_blocks(ctx->vi, bh->b_folio, bh->b_size,
bh_offset(bh));
end_buffer_async_read(bh, valid);
kfree(ctx);
}
-static void decrypt_bh(struct work_struct *work)
-{
- struct postprocess_bh_ctx *ctx =
- container_of(work, struct postprocess_bh_ctx, work);
- struct buffer_head *bh = ctx->bh;
- int err;
-
- err = fscrypt_decrypt_pagecache_blocks(bh->b_folio, bh->b_size,
- bh_offset(bh));
- if (err == 0 && ctx->vi) {
- /*
- * We use different work queues for decryption and for verity
- * because verity may require reading metadata pages that need
- * decryption, and we shouldn't recurse to the same workqueue.
- */
- INIT_WORK(&ctx->work, verify_bh);
- fsverity_enqueue_verify_work(&ctx->work);
- return;
- }
- end_buffer_async_read(bh, err == 0);
- kfree(ctx);
-}
-
/*
* I/O completion handler for block_read_full_folio() - folios
* which come unlocked at the end of I/O.
*/
static void bh_end_async_read(struct bio *bio)
{
struct buffer_head *bh;
bool uptodate = bio_endio_bh(bio, &bh);
struct inode *inode = bh->b_folio->mapping->host;
- bool decrypt = fscrypt_inode_uses_fs_layer_crypto(inode);
struct fsverity_info *vi = NULL;
/* needed by ext4 */
if (bh->b_folio->index < DIV_ROUND_UP(inode->i_size, PAGE_SIZE))
vi = fsverity_get_info(inode);
- /* Decrypt (with fscrypt) and/or verify (with fsverity) if needed. */
- if (uptodate && (decrypt || vi)) {
- struct postprocess_bh_ctx *ctx = kmalloc_obj(*ctx, GFP_ATOMIC);
+ /* Verify (with fsverity) if needed. */
+ if (vi && uptodate) {
+ struct verify_bh_ctx *ctx = kmalloc_obj(*ctx, GFP_ATOMIC);
if (ctx) {
ctx->bh = bh;
ctx->vi = vi;
- if (decrypt) {
- INIT_WORK(&ctx->work, decrypt_bh);
- fscrypt_enqueue_decrypt_work(&ctx->work);
- } else {
- INIT_WORK(&ctx->work, verify_bh);
- fsverity_enqueue_verify_work(&ctx->work);
- }
+ INIT_WORK(&ctx->work, verify_bh);
+ fsverity_enqueue_verify_work(&ctx->work);
return;
}
uptodate = false;
}
end_buffer_async_read(bh, uptodate);
--
2.54.0
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 11/16] fscrypt: Replace calls to fscrypt_inode_uses_inline_crypto()
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
-1 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: linux-fsdevel, linux-ext4, linux-f2fs-devel, linux-block,
Christoph Hellwig, Theodore Ts'o, Andreas Dilger, Baokun Li,
Jan Kara, Ojaswin Mujoo, Ritesh Harjani, Zhang Yi, Jaegeuk Kim,
Chao Yu, Eric Biggers
Now that fscrypt's file contents en/decryption is always implemented
using blk-crypto when the filesystem is block-based, the calls to
fscrypt_inode_uses_inline_crypto() in fs/crypto/inline_crypt.c (which
contains functions that are called only from block-based filesystems)
are equivalent to checking whether the file is an encrypted regular
file, i.e. fscrypt_needs_contents_encryption(). Use that instead.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
fs/crypto/inline_crypt.c | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c
index caf706215621..111ea45732f0 100644
--- a/fs/crypto/inline_crypt.c
+++ b/fs/crypto/inline_crypt.c
@@ -225,12 +225,12 @@ static void fscrypt_generate_dun(const struct fscrypt_inode_info *ci,
* @inode: the file's inode
* @pos: the first file position (in bytes) in the I/O
* @gfp_mask: memory allocation flags - these must be a waiting mask so that
* bio_crypt_set_ctx can't fail.
*
- * If the contents of the file should be encrypted (or decrypted) with inline
- * encryption, then assign the appropriate encryption context to the bio.
+ * If the contents of the file should be encrypted (or decrypted), then assign
+ * the appropriate encryption context to the bio.
*
* Normally the bio should be newly allocated (i.e. no pages added yet), as
* otherwise fscrypt_mergeable_bio() won't work as intended.
*
* The encryption context will be freed automatically when the bio is freed.
@@ -239,11 +239,11 @@ void fscrypt_set_bio_crypt_ctx(struct bio *bio, const struct inode *inode,
loff_t pos, gfp_t gfp_mask)
{
const struct fscrypt_inode_info *ci;
u64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE];
- if (!fscrypt_inode_uses_inline_crypto(inode))
+ if (!fscrypt_needs_contents_encryption(inode))
return;
ci = fscrypt_get_inode_info_raw(inode);
fscrypt_generate_dun(ci, pos, dun);
bio_crypt_set_ctx(bio, ci->ci_enc_key.blk_key, dun, gfp_mask);
@@ -254,16 +254,16 @@ EXPORT_SYMBOL_GPL(fscrypt_set_bio_crypt_ctx);
* fscrypt_mergeable_bio() - test whether data can be added to a bio
* @bio: the bio being built up
* @inode: the inode for the next part of the I/O
* @pos: the next file position (in bytes) in the I/O
*
- * When building a bio which may contain data which should undergo inline
- * encryption (or decryption) via fscrypt, filesystems should call this function
- * to ensure that the resulting bio contains only contiguous data unit numbers.
- * This will return false if the next part of the I/O cannot be merged with the
- * bio because either the encryption key would be different or the encryption
- * data unit numbers would be discontiguous.
+ * When building a bio which may contain data which should undergo encryption
+ * (or decryption) via fscrypt, filesystems should call this function to ensure
+ * that the resulting bio contains only contiguous data unit numbers. This will
+ * return false if the next part of the I/O cannot be merged with the bio
+ * because either the encryption key would be different or the encryption data
+ * unit numbers would be discontiguous.
*
* fscrypt_set_bio_crypt_ctx() must have already been called on the bio.
*
* This function isn't required in cases where crypto-mergeability is ensured in
* another way, such as I/O targeting only a single file (and thus a single key)
@@ -276,11 +276,11 @@ bool fscrypt_mergeable_bio(struct bio *bio, const struct inode *inode,
{
const struct bio_crypt_ctx *bc = bio->bi_crypt_context;
const struct fscrypt_inode_info *ci;
u64 next_dun[BLK_CRYPTO_DUN_ARRAY_SIZE];
- if (!!bc != fscrypt_inode_uses_inline_crypto(inode))
+ if (!!bc != fscrypt_needs_contents_encryption(inode))
return false;
if (!bc)
return true;
ci = fscrypt_get_inode_info_raw(inode);
@@ -334,11 +334,11 @@ bool fscrypt_dio_supported(struct inode *inode)
* Key unavailable or couldn't be set up. This edge case isn't
* worth worrying about; just report that DIO is unsupported.
*/
return false;
}
- return fscrypt_inode_uses_inline_crypto(inode);
+ return true;
}
EXPORT_SYMBOL_GPL(fscrypt_dio_supported);
/**
* fscrypt_limit_io_blocks() - limit I/O blocks to avoid discontiguous DUNs
@@ -363,11 +363,11 @@ EXPORT_SYMBOL_GPL(fscrypt_dio_supported);
u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk, u64 nr_blocks)
{
const struct fscrypt_inode_info *ci;
u32 dun;
- if (!fscrypt_inode_uses_inline_crypto(inode))
+ if (!fscrypt_needs_contents_encryption(inode))
return nr_blocks;
if (nr_blocks <= 1)
return nr_blocks;
--
2.54.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [f2fs-dev] [PATCH 11/16] fscrypt: Replace calls to fscrypt_inode_uses_inline_crypto()
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
0 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers via Linux-f2fs-devel @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: Ritesh Harjani, Theodore Ts'o, Zhang Yi, linux-f2fs-devel,
linux-block, Andreas Dilger, Ojaswin Mujoo, Baokun Li,
Jaegeuk Kim, linux-fsdevel, Jan Kara, linux-ext4,
Christoph Hellwig, Eric Biggers
Now that fscrypt's file contents en/decryption is always implemented
using blk-crypto when the filesystem is block-based, the calls to
fscrypt_inode_uses_inline_crypto() in fs/crypto/inline_crypt.c (which
contains functions that are called only from block-based filesystems)
are equivalent to checking whether the file is an encrypted regular
file, i.e. fscrypt_needs_contents_encryption(). Use that instead.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
fs/crypto/inline_crypt.c | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c
index caf706215621..111ea45732f0 100644
--- a/fs/crypto/inline_crypt.c
+++ b/fs/crypto/inline_crypt.c
@@ -225,12 +225,12 @@ static void fscrypt_generate_dun(const struct fscrypt_inode_info *ci,
* @inode: the file's inode
* @pos: the first file position (in bytes) in the I/O
* @gfp_mask: memory allocation flags - these must be a waiting mask so that
* bio_crypt_set_ctx can't fail.
*
- * If the contents of the file should be encrypted (or decrypted) with inline
- * encryption, then assign the appropriate encryption context to the bio.
+ * If the contents of the file should be encrypted (or decrypted), then assign
+ * the appropriate encryption context to the bio.
*
* Normally the bio should be newly allocated (i.e. no pages added yet), as
* otherwise fscrypt_mergeable_bio() won't work as intended.
*
* The encryption context will be freed automatically when the bio is freed.
@@ -239,11 +239,11 @@ void fscrypt_set_bio_crypt_ctx(struct bio *bio, const struct inode *inode,
loff_t pos, gfp_t gfp_mask)
{
const struct fscrypt_inode_info *ci;
u64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE];
- if (!fscrypt_inode_uses_inline_crypto(inode))
+ if (!fscrypt_needs_contents_encryption(inode))
return;
ci = fscrypt_get_inode_info_raw(inode);
fscrypt_generate_dun(ci, pos, dun);
bio_crypt_set_ctx(bio, ci->ci_enc_key.blk_key, dun, gfp_mask);
@@ -254,16 +254,16 @@ EXPORT_SYMBOL_GPL(fscrypt_set_bio_crypt_ctx);
* fscrypt_mergeable_bio() - test whether data can be added to a bio
* @bio: the bio being built up
* @inode: the inode for the next part of the I/O
* @pos: the next file position (in bytes) in the I/O
*
- * When building a bio which may contain data which should undergo inline
- * encryption (or decryption) via fscrypt, filesystems should call this function
- * to ensure that the resulting bio contains only contiguous data unit numbers.
- * This will return false if the next part of the I/O cannot be merged with the
- * bio because either the encryption key would be different or the encryption
- * data unit numbers would be discontiguous.
+ * When building a bio which may contain data which should undergo encryption
+ * (or decryption) via fscrypt, filesystems should call this function to ensure
+ * that the resulting bio contains only contiguous data unit numbers. This will
+ * return false if the next part of the I/O cannot be merged with the bio
+ * because either the encryption key would be different or the encryption data
+ * unit numbers would be discontiguous.
*
* fscrypt_set_bio_crypt_ctx() must have already been called on the bio.
*
* This function isn't required in cases where crypto-mergeability is ensured in
* another way, such as I/O targeting only a single file (and thus a single key)
@@ -276,11 +276,11 @@ bool fscrypt_mergeable_bio(struct bio *bio, const struct inode *inode,
{
const struct bio_crypt_ctx *bc = bio->bi_crypt_context;
const struct fscrypt_inode_info *ci;
u64 next_dun[BLK_CRYPTO_DUN_ARRAY_SIZE];
- if (!!bc != fscrypt_inode_uses_inline_crypto(inode))
+ if (!!bc != fscrypt_needs_contents_encryption(inode))
return false;
if (!bc)
return true;
ci = fscrypt_get_inode_info_raw(inode);
@@ -334,11 +334,11 @@ bool fscrypt_dio_supported(struct inode *inode)
* Key unavailable or couldn't be set up. This edge case isn't
* worth worrying about; just report that DIO is unsupported.
*/
return false;
}
- return fscrypt_inode_uses_inline_crypto(inode);
+ return true;
}
EXPORT_SYMBOL_GPL(fscrypt_dio_supported);
/**
* fscrypt_limit_io_blocks() - limit I/O blocks to avoid discontiguous DUNs
@@ -363,11 +363,11 @@ EXPORT_SYMBOL_GPL(fscrypt_dio_supported);
u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk, u64 nr_blocks)
{
const struct fscrypt_inode_info *ci;
u32 dun;
- if (!fscrypt_inode_uses_inline_crypto(inode))
+ if (!fscrypt_needs_contents_encryption(inode))
return nr_blocks;
if (nr_blocks <= 1)
return nr_blocks;
--
2.54.0
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 12/16] fscrypt: Remove fscrypt_dio_supported()
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
-1 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: linux-fsdevel, linux-ext4, linux-f2fs-devel, linux-block,
Christoph Hellwig, Theodore Ts'o, Andreas Dilger, Baokun Li,
Jan Kara, Ojaswin Mujoo, Ritesh Harjani, Zhang Yi, Jaegeuk Kim,
Chao Yu, Eric Biggers
On block-based filesystems, fscrypt file contents encryption is now
always implemented using blk-crypto. This implementation supports
direct I/O.
Therefore, fscrypt_dio_supported() now always returns true, except in
the edge case where statx(STATX_DIOALIGN) is called on an encrypted
regular file that hasn't had its key set up. But that was really a
workaround rather than the desired behavior, so we can disregard it.
Thus, fscrypt_dio_supported() is no longer needed. Remove it.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
fs/crypto/inline_crypt.c | 43 ----------------------------------------
fs/ext4/inode.c | 5 +----
fs/f2fs/file.c | 2 --
include/linux/fscrypt.h | 7 -------
4 files changed, 1 insertion(+), 56 deletions(-)
diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c
index 111ea45732f0..3c3a46c5af42 100644
--- a/fs/crypto/inline_crypt.c
+++ b/fs/crypto/inline_crypt.c
@@ -295,53 +295,10 @@ bool fscrypt_mergeable_bio(struct bio *bio, const struct inode *inode,
fscrypt_generate_dun(ci, pos, next_dun);
return bio_crypt_dun_is_contiguous(bc, bio->bi_iter.bi_size, next_dun);
}
EXPORT_SYMBOL_GPL(fscrypt_mergeable_bio);
-/**
- * fscrypt_dio_supported() - check whether DIO (direct I/O) is supported on an
- * inode, as far as encryption is concerned
- * @inode: the inode in question
- *
- * Return: %true if there are no encryption constraints that prevent DIO from
- * being supported; %false if DIO is unsupported. (Note that in the
- * %true case, the filesystem might have other, non-encryption-related
- * constraints that prevent DIO from actually being supported. Also, on
- * encrypted files the filesystem is still responsible for only allowing
- * DIO when requests are filesystem-block-aligned.)
- */
-bool fscrypt_dio_supported(struct inode *inode)
-{
- int err;
-
- /* If the file is unencrypted, no veto from us. */
- if (!fscrypt_needs_contents_encryption(inode))
- return true;
-
- /*
- * We only support DIO with inline crypto, not fs-layer crypto.
- *
- * To determine whether the inode is using inline crypto, we have to set
- * up the key if it wasn't already done. This is because in the current
- * design of fscrypt, the decision of whether to use inline crypto or
- * not isn't made until the inode's encryption key is being set up. In
- * the DIO read/write case, the key will always be set up already, since
- * the file will be open. But in the case of statx(), the key might not
- * be set up yet, as the file might not have been opened yet.
- */
- err = fscrypt_require_key(inode);
- if (err) {
- /*
- * Key unavailable or couldn't be set up. This edge case isn't
- * worth worrying about; just report that DIO is unsupported.
- */
- return false;
- }
- return true;
-}
-EXPORT_SYMBOL_GPL(fscrypt_dio_supported);
-
/**
* fscrypt_limit_io_blocks() - limit I/O blocks to avoid discontiguous DUNs
* @inode: the file on which I/O is being done
* @lblk: the block at which the I/O is being started from
* @nr_blocks: the number of blocks we want to submit starting at @lblk
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index c6faa7c751ca..dd321aaa8779 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -6144,15 +6144,12 @@ u32 ext4_dio_alignment(struct inode *inode)
return 0;
if (ext4_should_journal_data(inode))
return 0;
if (ext4_has_inline_data(inode))
return 0;
- if (IS_ENCRYPTED(inode)) {
- if (!fscrypt_dio_supported(inode))
- return 0;
+ if (IS_ENCRYPTED(inode))
return i_blocksize(inode);
- }
return 1; /* use the iomap defaults */
}
int ext4_getattr(struct mnt_idmap *idmap, const struct path *path,
struct kstat *stat, u32 request_mask, unsigned int query_flags)
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index fb12c5c9affd..a726bc2ab66c 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -948,12 +948,10 @@ int f2fs_truncate(struct inode *inode)
static bool f2fs_force_buffered_io(struct inode *inode, int rw)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
- if (!fscrypt_dio_supported(inode))
- return true;
if (fsverity_active(inode))
return true;
if (f2fs_compressed_file(inode))
return true;
/*
diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h
index 8d19b95150f1..43bafdd67dd7 100644
--- a/include/linux/fscrypt.h
+++ b/include/linux/fscrypt.h
@@ -868,12 +868,10 @@ void fscrypt_set_bio_crypt_ctx(struct bio *bio, const struct inode *inode,
loff_t pos, gfp_t gfp_mask);
bool fscrypt_mergeable_bio(struct bio *bio, const struct inode *inode,
loff_t pos);
-bool fscrypt_dio_supported(struct inode *inode);
-
u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk, u64 nr_blocks);
#else /* CONFIG_FS_ENCRYPTION_INLINE_CRYPT */
static inline void fscrypt_set_bio_crypt_ctx(struct bio *bio,
@@ -885,15 +883,10 @@ static inline bool fscrypt_mergeable_bio(struct bio *bio,
loff_t pos)
{
return true;
}
-static inline bool fscrypt_dio_supported(struct inode *inode)
-{
- return !fscrypt_needs_contents_encryption(inode);
-}
-
static inline u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk,
u64 nr_blocks)
{
return nr_blocks;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [f2fs-dev] [PATCH 12/16] fscrypt: Remove fscrypt_dio_supported()
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
0 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers via Linux-f2fs-devel @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: Ritesh Harjani, Theodore Ts'o, Zhang Yi, linux-f2fs-devel,
linux-block, Andreas Dilger, Ojaswin Mujoo, Baokun Li,
Jaegeuk Kim, linux-fsdevel, Jan Kara, linux-ext4,
Christoph Hellwig, Eric Biggers
On block-based filesystems, fscrypt file contents encryption is now
always implemented using blk-crypto. This implementation supports
direct I/O.
Therefore, fscrypt_dio_supported() now always returns true, except in
the edge case where statx(STATX_DIOALIGN) is called on an encrypted
regular file that hasn't had its key set up. But that was really a
workaround rather than the desired behavior, so we can disregard it.
Thus, fscrypt_dio_supported() is no longer needed. Remove it.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
fs/crypto/inline_crypt.c | 43 ----------------------------------------
fs/ext4/inode.c | 5 +----
fs/f2fs/file.c | 2 --
include/linux/fscrypt.h | 7 -------
4 files changed, 1 insertion(+), 56 deletions(-)
diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c
index 111ea45732f0..3c3a46c5af42 100644
--- a/fs/crypto/inline_crypt.c
+++ b/fs/crypto/inline_crypt.c
@@ -295,53 +295,10 @@ bool fscrypt_mergeable_bio(struct bio *bio, const struct inode *inode,
fscrypt_generate_dun(ci, pos, next_dun);
return bio_crypt_dun_is_contiguous(bc, bio->bi_iter.bi_size, next_dun);
}
EXPORT_SYMBOL_GPL(fscrypt_mergeable_bio);
-/**
- * fscrypt_dio_supported() - check whether DIO (direct I/O) is supported on an
- * inode, as far as encryption is concerned
- * @inode: the inode in question
- *
- * Return: %true if there are no encryption constraints that prevent DIO from
- * being supported; %false if DIO is unsupported. (Note that in the
- * %true case, the filesystem might have other, non-encryption-related
- * constraints that prevent DIO from actually being supported. Also, on
- * encrypted files the filesystem is still responsible for only allowing
- * DIO when requests are filesystem-block-aligned.)
- */
-bool fscrypt_dio_supported(struct inode *inode)
-{
- int err;
-
- /* If the file is unencrypted, no veto from us. */
- if (!fscrypt_needs_contents_encryption(inode))
- return true;
-
- /*
- * We only support DIO with inline crypto, not fs-layer crypto.
- *
- * To determine whether the inode is using inline crypto, we have to set
- * up the key if it wasn't already done. This is because in the current
- * design of fscrypt, the decision of whether to use inline crypto or
- * not isn't made until the inode's encryption key is being set up. In
- * the DIO read/write case, the key will always be set up already, since
- * the file will be open. But in the case of statx(), the key might not
- * be set up yet, as the file might not have been opened yet.
- */
- err = fscrypt_require_key(inode);
- if (err) {
- /*
- * Key unavailable or couldn't be set up. This edge case isn't
- * worth worrying about; just report that DIO is unsupported.
- */
- return false;
- }
- return true;
-}
-EXPORT_SYMBOL_GPL(fscrypt_dio_supported);
-
/**
* fscrypt_limit_io_blocks() - limit I/O blocks to avoid discontiguous DUNs
* @inode: the file on which I/O is being done
* @lblk: the block at which the I/O is being started from
* @nr_blocks: the number of blocks we want to submit starting at @lblk
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index c6faa7c751ca..dd321aaa8779 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -6144,15 +6144,12 @@ u32 ext4_dio_alignment(struct inode *inode)
return 0;
if (ext4_should_journal_data(inode))
return 0;
if (ext4_has_inline_data(inode))
return 0;
- if (IS_ENCRYPTED(inode)) {
- if (!fscrypt_dio_supported(inode))
- return 0;
+ if (IS_ENCRYPTED(inode))
return i_blocksize(inode);
- }
return 1; /* use the iomap defaults */
}
int ext4_getattr(struct mnt_idmap *idmap, const struct path *path,
struct kstat *stat, u32 request_mask, unsigned int query_flags)
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index fb12c5c9affd..a726bc2ab66c 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -948,12 +948,10 @@ int f2fs_truncate(struct inode *inode)
static bool f2fs_force_buffered_io(struct inode *inode, int rw)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
- if (!fscrypt_dio_supported(inode))
- return true;
if (fsverity_active(inode))
return true;
if (f2fs_compressed_file(inode))
return true;
/*
diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h
index 8d19b95150f1..43bafdd67dd7 100644
--- a/include/linux/fscrypt.h
+++ b/include/linux/fscrypt.h
@@ -868,12 +868,10 @@ void fscrypt_set_bio_crypt_ctx(struct bio *bio, const struct inode *inode,
loff_t pos, gfp_t gfp_mask);
bool fscrypt_mergeable_bio(struct bio *bio, const struct inode *inode,
loff_t pos);
-bool fscrypt_dio_supported(struct inode *inode);
-
u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk, u64 nr_blocks);
#else /* CONFIG_FS_ENCRYPTION_INLINE_CRYPT */
static inline void fscrypt_set_bio_crypt_ctx(struct bio *bio,
@@ -885,15 +883,10 @@ static inline bool fscrypt_mergeable_bio(struct bio *bio,
loff_t pos)
{
return true;
}
-static inline bool fscrypt_dio_supported(struct inode *inode)
-{
- return !fscrypt_needs_contents_encryption(inode);
-}
-
static inline u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk,
u64 nr_blocks)
{
return nr_blocks;
}
--
2.54.0
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 13/16] fscrypt: Remove fs-layer zeroout code
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
-1 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: linux-fsdevel, linux-ext4, linux-f2fs-devel, linux-block,
Christoph Hellwig, Theodore Ts'o, Andreas Dilger, Baokun Li,
Jan Kara, Ojaswin Mujoo, Ritesh Harjani, Zhang Yi, Jaegeuk Kim,
Chao Yu, Eric Biggers
Now that fscrypt's file contents en/decryption is always implemented
using blk-crypto when the filesystem is block-based, the fs-layer
zeroout code in fs/crypto/bio.c is unused code. Remove it, then fold
fscrypt_zeroout_range_inline_crypt() into fscrypt_zeroout_range().
Then make fscrypt_alloc_bounce_page() and fscrypt_crypt_data_unit()
static, since they're no longer called from any other file.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
fs/crypto/bio.c | 134 +++++++-----------------------------
fs/crypto/crypto.c | 14 ++--
fs/crypto/fscrypt_private.h | 5 --
3 files changed, 32 insertions(+), 121 deletions(-)
diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c
index d07740680602..58b6b13eeedd 100644
--- a/fs/crypto/bio.c
+++ b/fs/crypto/bio.c
@@ -67,20 +67,40 @@ static void fscrypt_zeroout_range_end_io(struct bio *bio)
cmpxchg(&done->status, 0, bio->bi_status);
fscrypt_zeroout_range_done(done);
bio_put(bio);
}
-static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode,
- loff_t pos, sector_t sector,
- u64 len)
+/**
+ * fscrypt_zeroout_range() - zero out a range of blocks in an encrypted file
+ * @inode: the file's inode
+ * @pos: the first file position (in bytes) to zero out
+ * @sector: the first sector to zero out
+ * @len: bytes to zero out
+ *
+ * Zero out filesystem blocks in an encrypted regular file on-disk, i.e. write
+ * ciphertext blocks which decrypt to the all-zeroes block. The blocks must be
+ * both logically and physically contiguous. It's also assumed that the
+ * filesystem only uses a single block device, ->s_bdev. @len must be a
+ * multiple of the file system logical block size.
+ *
+ * Note that since each block uses a different IV, this involves writing a
+ * different ciphertext to each block; we can't simply reuse the same one.
+ *
+ * Return: 0 on success; -errno on failure.
+ */
+int fscrypt_zeroout_range(const struct inode *inode, loff_t pos,
+ sector_t sector, u64 len)
{
struct fscrypt_zero_done done = {
.pending = ATOMIC_INIT(1),
.done = COMPLETION_INITIALIZER_ONSTACK(done.done),
};
- while (len) {
+ if (len == 0)
+ return 0;
+
+ do {
struct bio *bio;
unsigned int n;
bio = bio_alloc(inode->i_sb->s_bdev, BIO_MAX_VECS, REQ_OP_WRITE,
GFP_NOFS);
@@ -100,117 +120,13 @@ static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode,
break;
}
atomic_inc(&done.pending);
blk_crypto_submit_bio(bio);
- }
+ } while (len);
fscrypt_zeroout_range_done(&done);
wait_for_completion(&done.done);
return blk_status_to_errno(done.status);
}
-
-/**
- * fscrypt_zeroout_range() - zero out a range of blocks in an encrypted file
- * @inode: the file's inode
- * @pos: the first file position (in bytes) to zero out
- * @sector: the first sector to zero out
- * @len: bytes to zero out
- *
- * Zero out filesystem blocks in an encrypted regular file on-disk, i.e. write
- * ciphertext blocks which decrypt to the all-zeroes block. The blocks must be
- * both logically and physically contiguous. It's also assumed that the
- * filesystem only uses a single block device, ->s_bdev. @len must be a
- * multiple of the file system logical block size.
- *
- * Note that since each block uses a different IV, this involves writing a
- * different ciphertext to each block; we can't simply reuse the same one.
- *
- * Return: 0 on success; -errno on failure.
- */
-int fscrypt_zeroout_range(const struct inode *inode, loff_t pos,
- sector_t sector, u64 len)
-{
- const struct fscrypt_inode_info *ci = fscrypt_get_inode_info_raw(inode);
- const unsigned int du_bits = ci->ci_data_unit_bits;
- const unsigned int du_size = 1U << du_bits;
- const unsigned int du_per_page_bits = PAGE_SHIFT - du_bits;
- const unsigned int du_per_page = 1U << du_per_page_bits;
- u64 du_index = pos >> du_bits;
- u64 du_remaining = len >> du_bits;
- struct page *pages[16]; /* write up to 16 pages at a time */
- unsigned int nr_pages;
- unsigned int i;
- unsigned int offset;
- struct bio *bio;
- int ret, err;
-
- if (len == 0)
- return 0;
-
- if (fscrypt_inode_uses_inline_crypto(inode))
- return fscrypt_zeroout_range_inline_crypt(inode, pos, sector,
- len);
-
- BUILD_BUG_ON(ARRAY_SIZE(pages) > BIO_MAX_VECS);
- nr_pages = min_t(u64, ARRAY_SIZE(pages),
- (du_remaining + du_per_page - 1) >> du_per_page_bits);
-
- /*
- * We need at least one page for ciphertext. Allocate the first one
- * from a mempool, with __GFP_DIRECT_RECLAIM set so that it can't fail.
- *
- * Any additional page allocations are allowed to fail, as they only
- * help performance, and waiting on the mempool for them could deadlock.
- */
- for (i = 0; i < nr_pages; i++) {
- pages[i] = fscrypt_alloc_bounce_page(i == 0 ? GFP_NOFS :
- GFP_NOWAIT);
- if (!pages[i])
- break;
- }
- nr_pages = i;
- if (WARN_ON_ONCE(nr_pages <= 0))
- return -EINVAL;
-
- /* This always succeeds since __GFP_DIRECT_RECLAIM is set. */
- bio = bio_alloc(inode->i_sb->s_bdev, nr_pages, REQ_OP_WRITE, GFP_NOFS);
-
- do {
- bio->bi_iter.bi_sector = sector;
-
- i = 0;
- offset = 0;
- do {
- err = fscrypt_crypt_data_unit(ci, FS_ENCRYPT, du_index,
- ZERO_PAGE(0), pages[i],
- du_size, offset);
- if (err)
- goto out;
- du_index++;
- sector += 1U << (du_bits - SECTOR_SHIFT);
- du_remaining--;
- offset += du_size;
- if (offset == PAGE_SIZE || du_remaining == 0) {
- ret = bio_add_page(bio, pages[i++], offset, 0);
- if (WARN_ON_ONCE(ret != offset)) {
- err = -EIO;
- goto out;
- }
- offset = 0;
- }
- } while (i != nr_pages && du_remaining != 0);
-
- err = submit_bio_wait(bio);
- if (err)
- goto out;
- bio_reset(bio, inode->i_sb->s_bdev, REQ_OP_WRITE);
- } while (du_remaining != 0);
- err = 0;
-out:
- bio_put(bio);
- for (i = 0; i < nr_pages; i++)
- fscrypt_free_bounce_page(pages[i]);
- return err;
-}
EXPORT_SYMBOL(fscrypt_zeroout_range);
diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c
index 94dd6c89ddcd..8c4660429418 100644
--- a/fs/crypto/crypto.c
+++ b/fs/crypto/crypto.c
@@ -47,11 +47,11 @@ void fscrypt_enqueue_decrypt_work(struct work_struct *work)
{
queue_work(fscrypt_read_workqueue, work);
}
EXPORT_SYMBOL(fscrypt_enqueue_decrypt_work);
-struct page *fscrypt_alloc_bounce_page(gfp_t gfp_flags)
+static struct page *fscrypt_alloc_bounce_page(gfp_t gfp_flags)
{
if (WARN_ON_ONCE(!fscrypt_bounce_page_pool)) {
/*
* Oops, the filesystem called a function that uses the bounce
* page pool, but it didn't set needs_bounce_pages.
@@ -63,12 +63,11 @@ struct page *fscrypt_alloc_bounce_page(gfp_t gfp_flags)
/**
* fscrypt_free_bounce_page() - free a ciphertext bounce page
* @bounce_page: the bounce page to free, or NULL
*
- * Free a bounce page that was allocated by fscrypt_encrypt_pagecache_blocks(),
- * or by fscrypt_alloc_bounce_page() directly.
+ * Free a bounce page that was allocated by fscrypt_encrypt_pagecache_blocks().
*/
void fscrypt_free_bounce_page(struct page *bounce_page)
{
if (!bounce_page)
return;
@@ -105,14 +104,15 @@ void fscrypt_generate_iv(union fscrypt_iv *iv, u64 index,
}
iv->index = cpu_to_le64(index);
}
/* Encrypt or decrypt a single "data unit" of file contents. */
-int fscrypt_crypt_data_unit(const struct fscrypt_inode_info *ci,
- fscrypt_direction_t rw, u64 index,
- struct page *src_page, struct page *dest_page,
- unsigned int len, unsigned int offs)
+static int fscrypt_crypt_data_unit(const struct fscrypt_inode_info *ci,
+ fscrypt_direction_t rw, u64 index,
+ struct page *src_page,
+ struct page *dest_page, unsigned int len,
+ unsigned int offs)
{
struct crypto_sync_skcipher *tfm = ci->ci_enc_key.tfm;
SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
union fscrypt_iv iv;
struct scatterlist dst, src;
diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h
index 57b7ae2cfafc..da9040407d4a 100644
--- a/fs/crypto/fscrypt_private.h
+++ b/fs/crypto/fscrypt_private.h
@@ -327,15 +327,10 @@ typedef enum {
} fscrypt_direction_t;
/* crypto.c */
extern struct kmem_cache *fscrypt_inode_info_cachep;
int fscrypt_initialize(struct super_block *sb);
-int fscrypt_crypt_data_unit(const struct fscrypt_inode_info *ci,
- fscrypt_direction_t rw, u64 index,
- struct page *src_page, struct page *dest_page,
- unsigned int len, unsigned int offs);
-struct page *fscrypt_alloc_bounce_page(gfp_t gfp_flags);
void __printf(3, 4) __cold
fscrypt_msg(const struct inode *inode, const char *level, const char *fmt, ...);
#define fscrypt_warn(inode, fmt, ...) \
--
2.54.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [f2fs-dev] [PATCH 13/16] fscrypt: Remove fs-layer zeroout code
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
0 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers via Linux-f2fs-devel @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: Ritesh Harjani, Theodore Ts'o, Zhang Yi, linux-f2fs-devel,
linux-block, Andreas Dilger, Ojaswin Mujoo, Baokun Li,
Jaegeuk Kim, linux-fsdevel, Jan Kara, linux-ext4,
Christoph Hellwig, Eric Biggers
Now that fscrypt's file contents en/decryption is always implemented
using blk-crypto when the filesystem is block-based, the fs-layer
zeroout code in fs/crypto/bio.c is unused code. Remove it, then fold
fscrypt_zeroout_range_inline_crypt() into fscrypt_zeroout_range().
Then make fscrypt_alloc_bounce_page() and fscrypt_crypt_data_unit()
static, since they're no longer called from any other file.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
fs/crypto/bio.c | 134 +++++++-----------------------------
fs/crypto/crypto.c | 14 ++--
fs/crypto/fscrypt_private.h | 5 --
3 files changed, 32 insertions(+), 121 deletions(-)
diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c
index d07740680602..58b6b13eeedd 100644
--- a/fs/crypto/bio.c
+++ b/fs/crypto/bio.c
@@ -67,20 +67,40 @@ static void fscrypt_zeroout_range_end_io(struct bio *bio)
cmpxchg(&done->status, 0, bio->bi_status);
fscrypt_zeroout_range_done(done);
bio_put(bio);
}
-static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode,
- loff_t pos, sector_t sector,
- u64 len)
+/**
+ * fscrypt_zeroout_range() - zero out a range of blocks in an encrypted file
+ * @inode: the file's inode
+ * @pos: the first file position (in bytes) to zero out
+ * @sector: the first sector to zero out
+ * @len: bytes to zero out
+ *
+ * Zero out filesystem blocks in an encrypted regular file on-disk, i.e. write
+ * ciphertext blocks which decrypt to the all-zeroes block. The blocks must be
+ * both logically and physically contiguous. It's also assumed that the
+ * filesystem only uses a single block device, ->s_bdev. @len must be a
+ * multiple of the file system logical block size.
+ *
+ * Note that since each block uses a different IV, this involves writing a
+ * different ciphertext to each block; we can't simply reuse the same one.
+ *
+ * Return: 0 on success; -errno on failure.
+ */
+int fscrypt_zeroout_range(const struct inode *inode, loff_t pos,
+ sector_t sector, u64 len)
{
struct fscrypt_zero_done done = {
.pending = ATOMIC_INIT(1),
.done = COMPLETION_INITIALIZER_ONSTACK(done.done),
};
- while (len) {
+ if (len == 0)
+ return 0;
+
+ do {
struct bio *bio;
unsigned int n;
bio = bio_alloc(inode->i_sb->s_bdev, BIO_MAX_VECS, REQ_OP_WRITE,
GFP_NOFS);
@@ -100,117 +120,13 @@ static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode,
break;
}
atomic_inc(&done.pending);
blk_crypto_submit_bio(bio);
- }
+ } while (len);
fscrypt_zeroout_range_done(&done);
wait_for_completion(&done.done);
return blk_status_to_errno(done.status);
}
-
-/**
- * fscrypt_zeroout_range() - zero out a range of blocks in an encrypted file
- * @inode: the file's inode
- * @pos: the first file position (in bytes) to zero out
- * @sector: the first sector to zero out
- * @len: bytes to zero out
- *
- * Zero out filesystem blocks in an encrypted regular file on-disk, i.e. write
- * ciphertext blocks which decrypt to the all-zeroes block. The blocks must be
- * both logically and physically contiguous. It's also assumed that the
- * filesystem only uses a single block device, ->s_bdev. @len must be a
- * multiple of the file system logical block size.
- *
- * Note that since each block uses a different IV, this involves writing a
- * different ciphertext to each block; we can't simply reuse the same one.
- *
- * Return: 0 on success; -errno on failure.
- */
-int fscrypt_zeroout_range(const struct inode *inode, loff_t pos,
- sector_t sector, u64 len)
-{
- const struct fscrypt_inode_info *ci = fscrypt_get_inode_info_raw(inode);
- const unsigned int du_bits = ci->ci_data_unit_bits;
- const unsigned int du_size = 1U << du_bits;
- const unsigned int du_per_page_bits = PAGE_SHIFT - du_bits;
- const unsigned int du_per_page = 1U << du_per_page_bits;
- u64 du_index = pos >> du_bits;
- u64 du_remaining = len >> du_bits;
- struct page *pages[16]; /* write up to 16 pages at a time */
- unsigned int nr_pages;
- unsigned int i;
- unsigned int offset;
- struct bio *bio;
- int ret, err;
-
- if (len == 0)
- return 0;
-
- if (fscrypt_inode_uses_inline_crypto(inode))
- return fscrypt_zeroout_range_inline_crypt(inode, pos, sector,
- len);
-
- BUILD_BUG_ON(ARRAY_SIZE(pages) > BIO_MAX_VECS);
- nr_pages = min_t(u64, ARRAY_SIZE(pages),
- (du_remaining + du_per_page - 1) >> du_per_page_bits);
-
- /*
- * We need at least one page for ciphertext. Allocate the first one
- * from a mempool, with __GFP_DIRECT_RECLAIM set so that it can't fail.
- *
- * Any additional page allocations are allowed to fail, as they only
- * help performance, and waiting on the mempool for them could deadlock.
- */
- for (i = 0; i < nr_pages; i++) {
- pages[i] = fscrypt_alloc_bounce_page(i == 0 ? GFP_NOFS :
- GFP_NOWAIT);
- if (!pages[i])
- break;
- }
- nr_pages = i;
- if (WARN_ON_ONCE(nr_pages <= 0))
- return -EINVAL;
-
- /* This always succeeds since __GFP_DIRECT_RECLAIM is set. */
- bio = bio_alloc(inode->i_sb->s_bdev, nr_pages, REQ_OP_WRITE, GFP_NOFS);
-
- do {
- bio->bi_iter.bi_sector = sector;
-
- i = 0;
- offset = 0;
- do {
- err = fscrypt_crypt_data_unit(ci, FS_ENCRYPT, du_index,
- ZERO_PAGE(0), pages[i],
- du_size, offset);
- if (err)
- goto out;
- du_index++;
- sector += 1U << (du_bits - SECTOR_SHIFT);
- du_remaining--;
- offset += du_size;
- if (offset == PAGE_SIZE || du_remaining == 0) {
- ret = bio_add_page(bio, pages[i++], offset, 0);
- if (WARN_ON_ONCE(ret != offset)) {
- err = -EIO;
- goto out;
- }
- offset = 0;
- }
- } while (i != nr_pages && du_remaining != 0);
-
- err = submit_bio_wait(bio);
- if (err)
- goto out;
- bio_reset(bio, inode->i_sb->s_bdev, REQ_OP_WRITE);
- } while (du_remaining != 0);
- err = 0;
-out:
- bio_put(bio);
- for (i = 0; i < nr_pages; i++)
- fscrypt_free_bounce_page(pages[i]);
- return err;
-}
EXPORT_SYMBOL(fscrypt_zeroout_range);
diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c
index 94dd6c89ddcd..8c4660429418 100644
--- a/fs/crypto/crypto.c
+++ b/fs/crypto/crypto.c
@@ -47,11 +47,11 @@ void fscrypt_enqueue_decrypt_work(struct work_struct *work)
{
queue_work(fscrypt_read_workqueue, work);
}
EXPORT_SYMBOL(fscrypt_enqueue_decrypt_work);
-struct page *fscrypt_alloc_bounce_page(gfp_t gfp_flags)
+static struct page *fscrypt_alloc_bounce_page(gfp_t gfp_flags)
{
if (WARN_ON_ONCE(!fscrypt_bounce_page_pool)) {
/*
* Oops, the filesystem called a function that uses the bounce
* page pool, but it didn't set needs_bounce_pages.
@@ -63,12 +63,11 @@ struct page *fscrypt_alloc_bounce_page(gfp_t gfp_flags)
/**
* fscrypt_free_bounce_page() - free a ciphertext bounce page
* @bounce_page: the bounce page to free, or NULL
*
- * Free a bounce page that was allocated by fscrypt_encrypt_pagecache_blocks(),
- * or by fscrypt_alloc_bounce_page() directly.
+ * Free a bounce page that was allocated by fscrypt_encrypt_pagecache_blocks().
*/
void fscrypt_free_bounce_page(struct page *bounce_page)
{
if (!bounce_page)
return;
@@ -105,14 +104,15 @@ void fscrypt_generate_iv(union fscrypt_iv *iv, u64 index,
}
iv->index = cpu_to_le64(index);
}
/* Encrypt or decrypt a single "data unit" of file contents. */
-int fscrypt_crypt_data_unit(const struct fscrypt_inode_info *ci,
- fscrypt_direction_t rw, u64 index,
- struct page *src_page, struct page *dest_page,
- unsigned int len, unsigned int offs)
+static int fscrypt_crypt_data_unit(const struct fscrypt_inode_info *ci,
+ fscrypt_direction_t rw, u64 index,
+ struct page *src_page,
+ struct page *dest_page, unsigned int len,
+ unsigned int offs)
{
struct crypto_sync_skcipher *tfm = ci->ci_enc_key.tfm;
SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
union fscrypt_iv iv;
struct scatterlist dst, src;
diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h
index 57b7ae2cfafc..da9040407d4a 100644
--- a/fs/crypto/fscrypt_private.h
+++ b/fs/crypto/fscrypt_private.h
@@ -327,15 +327,10 @@ typedef enum {
} fscrypt_direction_t;
/* crypto.c */
extern struct kmem_cache *fscrypt_inode_info_cachep;
int fscrypt_initialize(struct super_block *sb);
-int fscrypt_crypt_data_unit(const struct fscrypt_inode_info *ci,
- fscrypt_direction_t rw, u64 index,
- struct page *src_page, struct page *dest_page,
- unsigned int len, unsigned int offs);
-struct page *fscrypt_alloc_bounce_page(gfp_t gfp_flags);
void __printf(3, 4) __cold
fscrypt_msg(const struct inode *inode, const char *level, const char *fmt, ...);
#define fscrypt_warn(inode, fmt, ...) \
--
2.54.0
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 14/16] fscrypt: Remove unused functions and workqueue
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
-1 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: linux-fsdevel, linux-ext4, linux-f2fs-devel, linux-block,
Christoph Hellwig, Theodore Ts'o, Andreas Dilger, Baokun Li,
Jan Kara, Ojaswin Mujoo, Ritesh Harjani, Zhang Yi, Jaegeuk Kim,
Chao Yu, Eric Biggers
Remove functions that are no longer used:
- fscrypt_decrypt_bio()
- fscrypt_decrypt_pagecache_blocks()
- fscrypt_inode_uses_fs_layer_crypto()
- fscrypt_inode_uses_inline_crypto()
- fscrypt_enqueue_decrypt_work()
This makes the decryption workqueue unused, so remove it too.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
fs/crypto/bio.c | 32 --------------------
fs/crypto/crypto.c | 65 -----------------------------------------
include/linux/fscrypt.h | 47 -----------------------------
3 files changed, 144 deletions(-)
diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c
index 58b6b13eeedd..db095258cfca 100644
--- a/fs/crypto/bio.c
+++ b/fs/crypto/bio.c
@@ -13,42 +13,10 @@
#include <linux/namei.h>
#include <linux/pagemap.h>
#include "fscrypt_private.h"
-/**
- * fscrypt_decrypt_bio() - decrypt the contents of a bio
- * @bio: the bio to decrypt
- *
- * Decrypt the contents of a "read" bio following successful completion of the
- * underlying disk read. The bio must be reading a whole number of blocks of an
- * encrypted file directly into the page cache. If the bio is reading the
- * ciphertext into bounce pages instead of the page cache (for example, because
- * the file is also compressed, so decompression is required after decryption),
- * then this function isn't applicable. This function may sleep, so it must be
- * called from a workqueue rather than from the bio's bi_end_io callback.
- *
- * Return: %true on success; %false on failure. On failure, bio->bi_status is
- * also set to an error status.
- */
-bool fscrypt_decrypt_bio(struct bio *bio)
-{
- struct folio_iter fi;
-
- bio_for_each_folio_all(fi, bio) {
- int err = fscrypt_decrypt_pagecache_blocks(fi.folio, fi.length,
- fi.offset);
-
- if (err) {
- bio->bi_status = errno_to_blk_status(err);
- return false;
- }
- }
- return true;
-}
-EXPORT_SYMBOL(fscrypt_decrypt_bio);
-
struct fscrypt_zero_done {
atomic_t pending;
blk_status_t status;
struct completion done;
};
diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c
index 8c4660429418..27663f4d8705 100644
--- a/fs/crypto/crypto.c
+++ b/fs/crypto/crypto.c
@@ -36,21 +36,14 @@ module_param(num_prealloc_crypto_pages, uint, 0444);
MODULE_PARM_DESC(num_prealloc_crypto_pages,
"Number of crypto pages to preallocate");
static mempool_t *fscrypt_bounce_page_pool = NULL;
-static struct workqueue_struct *fscrypt_read_workqueue;
static DEFINE_MUTEX(fscrypt_init_mutex);
struct kmem_cache *fscrypt_inode_info_cachep;
-void fscrypt_enqueue_decrypt_work(struct work_struct *work)
-{
- queue_work(fscrypt_read_workqueue, work);
-}
-EXPORT_SYMBOL(fscrypt_enqueue_decrypt_work);
-
static struct page *fscrypt_alloc_bounce_page(gfp_t gfp_flags)
{
if (WARN_ON_ONCE(!fscrypt_bounce_page_pool)) {
/*
* Oops, the filesystem called a function that uses the bounce
@@ -236,54 +229,10 @@ int fscrypt_encrypt_block_inplace(const struct inode *inode, struct page *page,
FS_ENCRYPT, lblk_num, page, page, len,
offs);
}
EXPORT_SYMBOL(fscrypt_encrypt_block_inplace);
-/**
- * fscrypt_decrypt_pagecache_blocks() - Decrypt data from a pagecache folio
- * @folio: the pagecache folio containing the data to decrypt
- * @len: size of the data to decrypt, in bytes
- * @offs: offset within @folio of the data to decrypt, in bytes
- *
- * Decrypt data that has just been read from an encrypted file. The data must
- * be located in a pagecache folio that is still locked and not yet uptodate.
- * The length and offset of the data must be aligned to the file's crypto data
- * unit size. Alignment to the filesystem block size fulfills this requirement,
- * as the filesystem block size is always a multiple of the data unit size.
- *
- * Return: 0 on success; -errno on failure
- */
-int fscrypt_decrypt_pagecache_blocks(struct folio *folio, size_t len,
- size_t offs)
-{
- const struct inode *inode = folio->mapping->host;
- const struct fscrypt_inode_info *ci = fscrypt_get_inode_info_raw(inode);
- const unsigned int du_bits = ci->ci_data_unit_bits;
- const unsigned int du_size = 1U << du_bits;
- u64 index = ((u64)folio->index << (PAGE_SHIFT - du_bits)) +
- (offs >> du_bits);
- size_t i;
- int err;
-
- if (WARN_ON_ONCE(!folio_test_locked(folio)))
- return -EINVAL;
-
- if (WARN_ON_ONCE(len <= 0 || !IS_ALIGNED(len | offs, du_size)))
- return -EINVAL;
-
- for (i = offs; i < offs + len; i += du_size, index++) {
- struct page *page = folio_page(folio, i >> PAGE_SHIFT);
-
- err = fscrypt_crypt_data_unit(ci, FS_DECRYPT, index, page,
- page, du_size, i & ~PAGE_MASK);
- if (err)
- return err;
- }
- return 0;
-}
-EXPORT_SYMBOL(fscrypt_decrypt_pagecache_blocks);
-
/**
* fscrypt_decrypt_block_inplace() - Decrypt a filesystem block in-place
* @inode: The inode to which this block belongs
* @page: The page containing the block to decrypt
* @len: Size of block to decrypt. This must be a multiple of
@@ -369,24 +318,10 @@ void fscrypt_msg(const struct inode *inode, const char *level,
va_end(args);
}
static int __init fscrypt_init(void)
{
- /*
- * Use an unbound workqueue to allow bios to be decrypted in parallel
- * even when they happen to complete on the same CPU. This sacrifices
- * locality, but it's worthwhile since decryption is CPU-intensive.
- *
- * Also use a high-priority workqueue to prioritize decryption work,
- * which blocks reads from completing, over regular application tasks.
- */
- fscrypt_read_workqueue = alloc_workqueue("fscrypt_read_queue",
- WQ_UNBOUND | WQ_HIGHPRI,
- num_online_cpus());
- if (!fscrypt_read_workqueue)
- panic("failed to allocate fscrypt_read_queue");
-
fscrypt_inode_info_cachep = KMEM_CACHE(fscrypt_inode_info,
SLAB_RECLAIM_ACCOUNT |
SLAB_PANIC);
fscrypt_init_keyring();
return 0;
diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h
index 43bafdd67dd7..acf5b28eb9d7 100644
--- a/include/linux/fscrypt.h
+++ b/include/linux/fscrypt.h
@@ -341,20 +341,17 @@ static inline void fscrypt_prepare_dentry(struct dentry *dentry,
spin_unlock(&dentry->d_lock);
}
}
/* crypto.c */
-void fscrypt_enqueue_decrypt_work(struct work_struct *);
struct page *fscrypt_encrypt_pagecache_blocks(struct folio *folio,
size_t len, size_t offs, gfp_t gfp_flags);
int fscrypt_encrypt_block_inplace(const struct inode *inode, struct page *page,
unsigned int len, unsigned int offs,
u64 lblk_num);
-int fscrypt_decrypt_pagecache_blocks(struct folio *folio, size_t len,
- size_t offs);
int fscrypt_decrypt_block_inplace(const struct inode *inode, struct page *page,
unsigned int len, unsigned int offs,
u64 lblk_num);
static inline bool fscrypt_is_bounce_page(struct page *page)
@@ -448,11 +445,10 @@ int fscrypt_fname_disk_to_usr(const struct inode *inode,
bool fscrypt_match_name(const struct fscrypt_name *fname,
const u8 *de_name, u32 de_name_len);
u64 fscrypt_fname_siphash(const struct inode *dir, const struct qstr *name);
/* bio.c */
-bool fscrypt_decrypt_bio(struct bio *bio);
int fscrypt_zeroout_range(const struct inode *inode, loff_t pos,
sector_t sector, u64 len);
/* hooks.c */
int fscrypt_file_open(struct inode *inode, struct file *filp);
@@ -508,13 +504,10 @@ static inline void fscrypt_prepare_dentry(struct dentry *dentry,
bool is_nokey_name)
{
}
/* crypto.c */
-static inline void fscrypt_enqueue_decrypt_work(struct work_struct *work)
-{
-}
static inline struct page *fscrypt_encrypt_pagecache_blocks(struct folio *folio,
size_t len, size_t offs, gfp_t gfp_flags)
{
return ERR_PTR(-EOPNOTSUPP);
@@ -526,16 +519,10 @@ static inline int fscrypt_encrypt_block_inplace(const struct inode *inode,
unsigned int offs, u64 lblk_num)
{
return -EOPNOTSUPP;
}
-static inline int fscrypt_decrypt_pagecache_blocks(struct folio *folio,
- size_t len, size_t offs)
-{
- return -EOPNOTSUPP;
-}
-
static inline int fscrypt_decrypt_block_inplace(const struct inode *inode,
struct page *page,
unsigned int len,
unsigned int offs, u64 lblk_num)
{
@@ -749,14 +736,10 @@ static inline int fscrypt_d_revalidate(struct inode *dir, const struct qstr *nam
{
return 1;
}
/* bio.c */
-static inline bool fscrypt_decrypt_bio(struct bio *bio)
-{
- return true;
-}
static inline int fscrypt_zeroout_range(const struct inode *inode, loff_t pos,
sector_t sector, u64 len)
{
return -EOPNOTSUPP;
@@ -890,40 +873,10 @@ static inline u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk,
{
return nr_blocks;
}
#endif /* !CONFIG_FS_ENCRYPTION_INLINE_CRYPT */
-/**
- * fscrypt_inode_uses_inline_crypto() - test whether an inode uses inline
- * encryption
- * @inode: an inode. If encrypted, its key must be set up.
- *
- * Return: true if the inode requires file contents encryption and if the
- * encryption should be done in the block layer via blk-crypto rather
- * than in the filesystem layer.
- */
-static inline bool fscrypt_inode_uses_inline_crypto(const struct inode *inode)
-{
- return fscrypt_needs_contents_encryption(inode) &&
- inode->i_sb->s_cop->is_block_based;
-}
-
-/**
- * fscrypt_inode_uses_fs_layer_crypto() - test whether an inode uses fs-layer
- * encryption
- * @inode: an inode. If encrypted, its key must be set up.
- *
- * Return: true if the inode requires file contents encryption and if the
- * encryption should be done in the filesystem layer rather than in the
- * block layer via blk-crypto.
- */
-static inline bool fscrypt_inode_uses_fs_layer_crypto(const struct inode *inode)
-{
- return fscrypt_needs_contents_encryption(inode) &&
- !inode->i_sb->s_cop->is_block_based;
-}
-
/**
* fscrypt_has_encryption_key() - check whether an inode has had its key set up
* @inode: the inode to check
*
* Return: %true if the inode has had its encryption key set up, else %false.
--
2.54.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [f2fs-dev] [PATCH 14/16] fscrypt: Remove unused functions and workqueue
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
0 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers via Linux-f2fs-devel @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: Ritesh Harjani, Theodore Ts'o, Zhang Yi, linux-f2fs-devel,
linux-block, Andreas Dilger, Ojaswin Mujoo, Baokun Li,
Jaegeuk Kim, linux-fsdevel, Jan Kara, linux-ext4,
Christoph Hellwig, Eric Biggers
Remove functions that are no longer used:
- fscrypt_decrypt_bio()
- fscrypt_decrypt_pagecache_blocks()
- fscrypt_inode_uses_fs_layer_crypto()
- fscrypt_inode_uses_inline_crypto()
- fscrypt_enqueue_decrypt_work()
This makes the decryption workqueue unused, so remove it too.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
fs/crypto/bio.c | 32 --------------------
fs/crypto/crypto.c | 65 -----------------------------------------
include/linux/fscrypt.h | 47 -----------------------------
3 files changed, 144 deletions(-)
diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c
index 58b6b13eeedd..db095258cfca 100644
--- a/fs/crypto/bio.c
+++ b/fs/crypto/bio.c
@@ -13,42 +13,10 @@
#include <linux/namei.h>
#include <linux/pagemap.h>
#include "fscrypt_private.h"
-/**
- * fscrypt_decrypt_bio() - decrypt the contents of a bio
- * @bio: the bio to decrypt
- *
- * Decrypt the contents of a "read" bio following successful completion of the
- * underlying disk read. The bio must be reading a whole number of blocks of an
- * encrypted file directly into the page cache. If the bio is reading the
- * ciphertext into bounce pages instead of the page cache (for example, because
- * the file is also compressed, so decompression is required after decryption),
- * then this function isn't applicable. This function may sleep, so it must be
- * called from a workqueue rather than from the bio's bi_end_io callback.
- *
- * Return: %true on success; %false on failure. On failure, bio->bi_status is
- * also set to an error status.
- */
-bool fscrypt_decrypt_bio(struct bio *bio)
-{
- struct folio_iter fi;
-
- bio_for_each_folio_all(fi, bio) {
- int err = fscrypt_decrypt_pagecache_blocks(fi.folio, fi.length,
- fi.offset);
-
- if (err) {
- bio->bi_status = errno_to_blk_status(err);
- return false;
- }
- }
- return true;
-}
-EXPORT_SYMBOL(fscrypt_decrypt_bio);
-
struct fscrypt_zero_done {
atomic_t pending;
blk_status_t status;
struct completion done;
};
diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c
index 8c4660429418..27663f4d8705 100644
--- a/fs/crypto/crypto.c
+++ b/fs/crypto/crypto.c
@@ -36,21 +36,14 @@ module_param(num_prealloc_crypto_pages, uint, 0444);
MODULE_PARM_DESC(num_prealloc_crypto_pages,
"Number of crypto pages to preallocate");
static mempool_t *fscrypt_bounce_page_pool = NULL;
-static struct workqueue_struct *fscrypt_read_workqueue;
static DEFINE_MUTEX(fscrypt_init_mutex);
struct kmem_cache *fscrypt_inode_info_cachep;
-void fscrypt_enqueue_decrypt_work(struct work_struct *work)
-{
- queue_work(fscrypt_read_workqueue, work);
-}
-EXPORT_SYMBOL(fscrypt_enqueue_decrypt_work);
-
static struct page *fscrypt_alloc_bounce_page(gfp_t gfp_flags)
{
if (WARN_ON_ONCE(!fscrypt_bounce_page_pool)) {
/*
* Oops, the filesystem called a function that uses the bounce
@@ -236,54 +229,10 @@ int fscrypt_encrypt_block_inplace(const struct inode *inode, struct page *page,
FS_ENCRYPT, lblk_num, page, page, len,
offs);
}
EXPORT_SYMBOL(fscrypt_encrypt_block_inplace);
-/**
- * fscrypt_decrypt_pagecache_blocks() - Decrypt data from a pagecache folio
- * @folio: the pagecache folio containing the data to decrypt
- * @len: size of the data to decrypt, in bytes
- * @offs: offset within @folio of the data to decrypt, in bytes
- *
- * Decrypt data that has just been read from an encrypted file. The data must
- * be located in a pagecache folio that is still locked and not yet uptodate.
- * The length and offset of the data must be aligned to the file's crypto data
- * unit size. Alignment to the filesystem block size fulfills this requirement,
- * as the filesystem block size is always a multiple of the data unit size.
- *
- * Return: 0 on success; -errno on failure
- */
-int fscrypt_decrypt_pagecache_blocks(struct folio *folio, size_t len,
- size_t offs)
-{
- const struct inode *inode = folio->mapping->host;
- const struct fscrypt_inode_info *ci = fscrypt_get_inode_info_raw(inode);
- const unsigned int du_bits = ci->ci_data_unit_bits;
- const unsigned int du_size = 1U << du_bits;
- u64 index = ((u64)folio->index << (PAGE_SHIFT - du_bits)) +
- (offs >> du_bits);
- size_t i;
- int err;
-
- if (WARN_ON_ONCE(!folio_test_locked(folio)))
- return -EINVAL;
-
- if (WARN_ON_ONCE(len <= 0 || !IS_ALIGNED(len | offs, du_size)))
- return -EINVAL;
-
- for (i = offs; i < offs + len; i += du_size, index++) {
- struct page *page = folio_page(folio, i >> PAGE_SHIFT);
-
- err = fscrypt_crypt_data_unit(ci, FS_DECRYPT, index, page,
- page, du_size, i & ~PAGE_MASK);
- if (err)
- return err;
- }
- return 0;
-}
-EXPORT_SYMBOL(fscrypt_decrypt_pagecache_blocks);
-
/**
* fscrypt_decrypt_block_inplace() - Decrypt a filesystem block in-place
* @inode: The inode to which this block belongs
* @page: The page containing the block to decrypt
* @len: Size of block to decrypt. This must be a multiple of
@@ -369,24 +318,10 @@ void fscrypt_msg(const struct inode *inode, const char *level,
va_end(args);
}
static int __init fscrypt_init(void)
{
- /*
- * Use an unbound workqueue to allow bios to be decrypted in parallel
- * even when they happen to complete on the same CPU. This sacrifices
- * locality, but it's worthwhile since decryption is CPU-intensive.
- *
- * Also use a high-priority workqueue to prioritize decryption work,
- * which blocks reads from completing, over regular application tasks.
- */
- fscrypt_read_workqueue = alloc_workqueue("fscrypt_read_queue",
- WQ_UNBOUND | WQ_HIGHPRI,
- num_online_cpus());
- if (!fscrypt_read_workqueue)
- panic("failed to allocate fscrypt_read_queue");
-
fscrypt_inode_info_cachep = KMEM_CACHE(fscrypt_inode_info,
SLAB_RECLAIM_ACCOUNT |
SLAB_PANIC);
fscrypt_init_keyring();
return 0;
diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h
index 43bafdd67dd7..acf5b28eb9d7 100644
--- a/include/linux/fscrypt.h
+++ b/include/linux/fscrypt.h
@@ -341,20 +341,17 @@ static inline void fscrypt_prepare_dentry(struct dentry *dentry,
spin_unlock(&dentry->d_lock);
}
}
/* crypto.c */
-void fscrypt_enqueue_decrypt_work(struct work_struct *);
struct page *fscrypt_encrypt_pagecache_blocks(struct folio *folio,
size_t len, size_t offs, gfp_t gfp_flags);
int fscrypt_encrypt_block_inplace(const struct inode *inode, struct page *page,
unsigned int len, unsigned int offs,
u64 lblk_num);
-int fscrypt_decrypt_pagecache_blocks(struct folio *folio, size_t len,
- size_t offs);
int fscrypt_decrypt_block_inplace(const struct inode *inode, struct page *page,
unsigned int len, unsigned int offs,
u64 lblk_num);
static inline bool fscrypt_is_bounce_page(struct page *page)
@@ -448,11 +445,10 @@ int fscrypt_fname_disk_to_usr(const struct inode *inode,
bool fscrypt_match_name(const struct fscrypt_name *fname,
const u8 *de_name, u32 de_name_len);
u64 fscrypt_fname_siphash(const struct inode *dir, const struct qstr *name);
/* bio.c */
-bool fscrypt_decrypt_bio(struct bio *bio);
int fscrypt_zeroout_range(const struct inode *inode, loff_t pos,
sector_t sector, u64 len);
/* hooks.c */
int fscrypt_file_open(struct inode *inode, struct file *filp);
@@ -508,13 +504,10 @@ static inline void fscrypt_prepare_dentry(struct dentry *dentry,
bool is_nokey_name)
{
}
/* crypto.c */
-static inline void fscrypt_enqueue_decrypt_work(struct work_struct *work)
-{
-}
static inline struct page *fscrypt_encrypt_pagecache_blocks(struct folio *folio,
size_t len, size_t offs, gfp_t gfp_flags)
{
return ERR_PTR(-EOPNOTSUPP);
@@ -526,16 +519,10 @@ static inline int fscrypt_encrypt_block_inplace(const struct inode *inode,
unsigned int offs, u64 lblk_num)
{
return -EOPNOTSUPP;
}
-static inline int fscrypt_decrypt_pagecache_blocks(struct folio *folio,
- size_t len, size_t offs)
-{
- return -EOPNOTSUPP;
-}
-
static inline int fscrypt_decrypt_block_inplace(const struct inode *inode,
struct page *page,
unsigned int len,
unsigned int offs, u64 lblk_num)
{
@@ -749,14 +736,10 @@ static inline int fscrypt_d_revalidate(struct inode *dir, const struct qstr *nam
{
return 1;
}
/* bio.c */
-static inline bool fscrypt_decrypt_bio(struct bio *bio)
-{
- return true;
-}
static inline int fscrypt_zeroout_range(const struct inode *inode, loff_t pos,
sector_t sector, u64 len)
{
return -EOPNOTSUPP;
@@ -890,40 +873,10 @@ static inline u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk,
{
return nr_blocks;
}
#endif /* !CONFIG_FS_ENCRYPTION_INLINE_CRYPT */
-/**
- * fscrypt_inode_uses_inline_crypto() - test whether an inode uses inline
- * encryption
- * @inode: an inode. If encrypted, its key must be set up.
- *
- * Return: true if the inode requires file contents encryption and if the
- * encryption should be done in the block layer via blk-crypto rather
- * than in the filesystem layer.
- */
-static inline bool fscrypt_inode_uses_inline_crypto(const struct inode *inode)
-{
- return fscrypt_needs_contents_encryption(inode) &&
- inode->i_sb->s_cop->is_block_based;
-}
-
-/**
- * fscrypt_inode_uses_fs_layer_crypto() - test whether an inode uses fs-layer
- * encryption
- * @inode: an inode. If encrypted, its key must be set up.
- *
- * Return: true if the inode requires file contents encryption and if the
- * encryption should be done in the filesystem layer rather than in the
- * block layer via blk-crypto.
- */
-static inline bool fscrypt_inode_uses_fs_layer_crypto(const struct inode *inode)
-{
- return fscrypt_needs_contents_encryption(inode) &&
- !inode->i_sb->s_cop->is_block_based;
-}
-
/**
* fscrypt_has_encryption_key() - check whether an inode has had its key set up
* @inode: the inode to check
*
* Return: %true if the inode has had its encryption key set up, else %false.
--
2.54.0
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 15/16] fscrypt: Merge bio.c and inline_crypt.c into block.c
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
-1 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: linux-fsdevel, linux-ext4, linux-f2fs-devel, linux-block,
Christoph Hellwig, Theodore Ts'o, Andreas Dilger, Baokun Li,
Jan Kara, Ojaswin Mujoo, Ritesh Harjani, Zhang Yi, Jaegeuk Kim,
Chao Yu, Eric Biggers
Now that fscrypt always uses blk-crypto on block-based filesystems,
there's no meaningful difference between bio.c and inline_crypt.c.
Therefore merge the two files into one named block.c.
Note: I didn't carry over bio.c's "Copyright (C) 2015, Motorola
Mobility", as none of the code that applied to remained.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
fs/crypto/Makefile | 3 +-
fs/crypto/bio.c | 100 --------------------------
fs/crypto/{inline_crypt.c => block.c} | 96 +++++++++++++++++++++++--
fs/crypto/fscrypt_private.h | 2 +-
include/linux/fscrypt.h | 22 +++---
5 files changed, 101 insertions(+), 122 deletions(-)
delete mode 100644 fs/crypto/bio.c
rename fs/crypto/{inline_crypt.c => block.c} (79%)
diff --git a/fs/crypto/Makefile b/fs/crypto/Makefile
index 652c7180ec6d..b03e02f0f09d 100644
--- a/fs/crypto/Makefile
+++ b/fs/crypto/Makefile
@@ -8,7 +8,6 @@ fscrypto-y := crypto.o \
keyring.o \
keysetup.o \
keysetup_v1.o \
policy.o
-fscrypto-$(CONFIG_BLOCK) += bio.o
-fscrypto-$(CONFIG_FS_ENCRYPTION_INLINE_CRYPT) += inline_crypt.o
+fscrypto-$(CONFIG_BLOCK) += block.o
diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c
deleted file mode 100644
index db095258cfca..000000000000
--- a/fs/crypto/bio.c
+++ /dev/null
@@ -1,100 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Utility functions for file contents encryption/decryption on
- * block device-based filesystems.
- *
- * Copyright (C) 2015, Google, Inc.
- * Copyright (C) 2015, Motorola Mobility
- */
-
-#include <linux/bio.h>
-#include <linux/export.h>
-#include <linux/module.h>
-#include <linux/namei.h>
-#include <linux/pagemap.h>
-
-#include "fscrypt_private.h"
-
-struct fscrypt_zero_done {
- atomic_t pending;
- blk_status_t status;
- struct completion done;
-};
-
-static void fscrypt_zeroout_range_done(struct fscrypt_zero_done *done)
-{
- if (atomic_dec_and_test(&done->pending))
- complete(&done->done);
-}
-
-static void fscrypt_zeroout_range_end_io(struct bio *bio)
-{
- struct fscrypt_zero_done *done = bio->bi_private;
-
- if (bio->bi_status)
- cmpxchg(&done->status, 0, bio->bi_status);
- fscrypt_zeroout_range_done(done);
- bio_put(bio);
-}
-
-/**
- * fscrypt_zeroout_range() - zero out a range of blocks in an encrypted file
- * @inode: the file's inode
- * @pos: the first file position (in bytes) to zero out
- * @sector: the first sector to zero out
- * @len: bytes to zero out
- *
- * Zero out filesystem blocks in an encrypted regular file on-disk, i.e. write
- * ciphertext blocks which decrypt to the all-zeroes block. The blocks must be
- * both logically and physically contiguous. It's also assumed that the
- * filesystem only uses a single block device, ->s_bdev. @len must be a
- * multiple of the file system logical block size.
- *
- * Note that since each block uses a different IV, this involves writing a
- * different ciphertext to each block; we can't simply reuse the same one.
- *
- * Return: 0 on success; -errno on failure.
- */
-int fscrypt_zeroout_range(const struct inode *inode, loff_t pos,
- sector_t sector, u64 len)
-{
- struct fscrypt_zero_done done = {
- .pending = ATOMIC_INIT(1),
- .done = COMPLETION_INITIALIZER_ONSTACK(done.done),
- };
-
- if (len == 0)
- return 0;
-
- do {
- struct bio *bio;
- unsigned int n;
-
- bio = bio_alloc(inode->i_sb->s_bdev, BIO_MAX_VECS, REQ_OP_WRITE,
- GFP_NOFS);
- bio->bi_iter.bi_sector = sector;
- bio->bi_private = &done;
- bio->bi_end_io = fscrypt_zeroout_range_end_io;
- fscrypt_set_bio_crypt_ctx(bio, inode, pos, GFP_NOFS);
-
- for (n = 0; n < BIO_MAX_VECS; n++) {
- unsigned int bytes_this_page = min(len, PAGE_SIZE);
-
- __bio_add_page(bio, ZERO_PAGE(0), bytes_this_page, 0);
- len -= bytes_this_page;
- pos += bytes_this_page;
- sector += (bytes_this_page >> SECTOR_SHIFT);
- if (!len || !fscrypt_mergeable_bio(bio, inode, pos))
- break;
- }
-
- atomic_inc(&done.pending);
- blk_crypto_submit_bio(bio);
- } while (len);
-
- fscrypt_zeroout_range_done(&done);
-
- wait_for_completion(&done.done);
- return blk_status_to_errno(done.status);
-}
-EXPORT_SYMBOL(fscrypt_zeroout_range);
diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/block.c
similarity index 79%
rename from fs/crypto/inline_crypt.c
rename to fs/crypto/block.c
index 3c3a46c5af42..60e687da7760 100644
--- a/fs/crypto/inline_crypt.c
+++ b/fs/crypto/block.c
@@ -1,22 +1,22 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Inline encryption support for fscrypt
+ * File contents en/decryption on block-based filesystems
*
* Copyright 2019 Google LLC
*/
/*
- * With "inline encryption", the block layer handles the decryption/encryption
- * as part of the bio, instead of the filesystem doing the crypto itself via
- * crypto API. See Documentation/block/inline-encryption.rst. fscrypt still
- * provides the key and IV to use.
+ * This file implements fscrypt's file contents en/decryption using blk-crypto
+ * (Documentation/block/inline-encryption.rst). fscrypt assigns a bio_crypt_ctx
+ * with a key and IV to each bio, and the block layer does the en/decryption.
+ *
+ * This file's exported functions are called only by block-based filesystems.
*/
#include <linux/blk-crypto.h>
#include <linux/blkdev.h>
-#include <linux/buffer_head.h>
#include <linux/export.h>
#include <linux/sched/mm.h>
#include <linux/slab.h>
#include <linux/uio.h>
@@ -338,5 +338,89 @@ u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk, u64 nr_blocks)
dun = ci->ci_hashed_ino + lblk;
return min_t(u64, nr_blocks, (u64)U32_MAX + 1 - dun);
}
EXPORT_SYMBOL_GPL(fscrypt_limit_io_blocks);
+
+struct fscrypt_zero_done {
+ atomic_t pending;
+ blk_status_t status;
+ struct completion done;
+};
+
+static void fscrypt_zeroout_range_done(struct fscrypt_zero_done *done)
+{
+ if (atomic_dec_and_test(&done->pending))
+ complete(&done->done);
+}
+
+static void fscrypt_zeroout_range_end_io(struct bio *bio)
+{
+ struct fscrypt_zero_done *done = bio->bi_private;
+
+ if (bio->bi_status)
+ cmpxchg(&done->status, 0, bio->bi_status);
+ fscrypt_zeroout_range_done(done);
+ bio_put(bio);
+}
+
+/**
+ * fscrypt_zeroout_range() - zero out a range of blocks in an encrypted file
+ * @inode: the file's inode
+ * @pos: the first file position (in bytes) to zero out
+ * @sector: the first sector to zero out
+ * @len: bytes to zero out
+ *
+ * Zero out filesystem blocks in an encrypted regular file on-disk, i.e. write
+ * ciphertext blocks which decrypt to the all-zeroes block. The blocks must be
+ * both logically and physically contiguous. It's also assumed that the
+ * filesystem only uses a single block device, ->s_bdev. @len must be a
+ * multiple of the file system logical block size.
+ *
+ * Note that since each block uses a different IV, this involves writing a
+ * different ciphertext to each block; we can't simply reuse the same one.
+ *
+ * Return: 0 on success; -errno on failure.
+ */
+int fscrypt_zeroout_range(const struct inode *inode, loff_t pos,
+ sector_t sector, u64 len)
+{
+ struct fscrypt_zero_done done = {
+ .pending = ATOMIC_INIT(1),
+ .done = COMPLETION_INITIALIZER_ONSTACK(done.done),
+ };
+
+ if (len == 0)
+ return 0;
+
+ do {
+ struct bio *bio;
+ unsigned int n;
+
+ bio = bio_alloc(inode->i_sb->s_bdev, BIO_MAX_VECS, REQ_OP_WRITE,
+ GFP_NOFS);
+ bio->bi_iter.bi_sector = sector;
+ bio->bi_private = &done;
+ bio->bi_end_io = fscrypt_zeroout_range_end_io;
+ fscrypt_set_bio_crypt_ctx(bio, inode, pos, GFP_NOFS);
+
+ for (n = 0; n < BIO_MAX_VECS; n++) {
+ unsigned int bytes_this_page = min(len, PAGE_SIZE);
+
+ __bio_add_page(bio, ZERO_PAGE(0), bytes_this_page, 0);
+ len -= bytes_this_page;
+ pos += bytes_this_page;
+ sector += (bytes_this_page >> SECTOR_SHIFT);
+ if (!len || !fscrypt_mergeable_bio(bio, inode, pos))
+ break;
+ }
+
+ atomic_inc(&done.pending);
+ blk_crypto_submit_bio(bio);
+ } while (len);
+
+ fscrypt_zeroout_range_done(&done);
+
+ wait_for_completion(&done.done);
+ return blk_status_to_errno(done.status);
+}
+EXPORT_SYMBOL(fscrypt_zeroout_range);
diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h
index da9040407d4a..74329e0953d1 100644
--- a/fs/crypto/fscrypt_private.h
+++ b/fs/crypto/fscrypt_private.h
@@ -393,11 +393,11 @@ void fscrypt_init_hkdf(struct hmac_sha512_key *hkdf, const u8 *master_key,
void fscrypt_hkdf_expand(const struct hmac_sha512_key *hkdf, u8 context,
const u8 *info, unsigned int infolen,
u8 *okm, unsigned int okmlen);
-/* inline_crypt.c */
+/* block.c */
#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT
static inline bool
fscrypt_using_inline_encryption(const struct fscrypt_inode_info *ci)
{
const struct inode *inode = ci->ci_inode;
diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h
index acf5b28eb9d7..52ff014aeae6 100644
--- a/include/linux/fscrypt.h
+++ b/include/linux/fscrypt.h
@@ -444,14 +444,10 @@ int fscrypt_fname_disk_to_usr(const struct inode *inode,
struct fscrypt_str *oname);
bool fscrypt_match_name(const struct fscrypt_name *fname,
const u8 *de_name, u32 de_name_len);
u64 fscrypt_fname_siphash(const struct inode *dir, const struct qstr *name);
-/* bio.c */
-int fscrypt_zeroout_range(const struct inode *inode, loff_t pos,
- sector_t sector, u64 len);
-
/* hooks.c */
int fscrypt_file_open(struct inode *inode, struct file *filp);
int __fscrypt_prepare_link(struct inode *inode, struct inode *dir,
struct dentry *dentry);
int __fscrypt_prepare_rename(struct inode *old_dir, struct dentry *old_dentry,
@@ -735,18 +731,10 @@ static inline int fscrypt_d_revalidate(struct inode *dir, const struct qstr *nam
struct dentry *dentry, unsigned int flags)
{
return 1;
}
-/* bio.c */
-
-static inline int fscrypt_zeroout_range(const struct inode *inode, loff_t pos,
- sector_t sector, u64 len)
-{
- return -EOPNOTSUPP;
-}
-
/* hooks.c */
static inline int fscrypt_file_open(struct inode *inode, struct file *filp)
{
if (IS_ENCRYPTED(inode))
@@ -842,20 +830,22 @@ static inline void fscrypt_set_ops(struct super_block *sb,
{
}
#endif /* !CONFIG_FS_ENCRYPTION */
-/* inline_crypt.c */
+/* block.c */
#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT
void fscrypt_set_bio_crypt_ctx(struct bio *bio, const struct inode *inode,
loff_t pos, gfp_t gfp_mask);
bool fscrypt_mergeable_bio(struct bio *bio, const struct inode *inode,
loff_t pos);
u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk, u64 nr_blocks);
+int fscrypt_zeroout_range(const struct inode *inode, loff_t pos,
+ sector_t sector, u64 len);
#else /* CONFIG_FS_ENCRYPTION_INLINE_CRYPT */
static inline void fscrypt_set_bio_crypt_ctx(struct bio *bio,
const struct inode *inode,
@@ -871,10 +861,16 @@ static inline bool fscrypt_mergeable_bio(struct bio *bio,
static inline u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk,
u64 nr_blocks)
{
return nr_blocks;
}
+
+static inline int fscrypt_zeroout_range(const struct inode *inode, loff_t pos,
+ sector_t sector, u64 len)
+{
+ return -EOPNOTSUPP;
+}
#endif /* !CONFIG_FS_ENCRYPTION_INLINE_CRYPT */
/**
* fscrypt_has_encryption_key() - check whether an inode has had its key set up
* @inode: the inode to check
--
2.54.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [f2fs-dev] [PATCH 15/16] fscrypt: Merge bio.c and inline_crypt.c into block.c
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
0 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers via Linux-f2fs-devel @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: Ritesh Harjani, Theodore Ts'o, Zhang Yi, linux-f2fs-devel,
linux-block, Andreas Dilger, Ojaswin Mujoo, Baokun Li,
Jaegeuk Kim, linux-fsdevel, Jan Kara, linux-ext4,
Christoph Hellwig, Eric Biggers
Now that fscrypt always uses blk-crypto on block-based filesystems,
there's no meaningful difference between bio.c and inline_crypt.c.
Therefore merge the two files into one named block.c.
Note: I didn't carry over bio.c's "Copyright (C) 2015, Motorola
Mobility", as none of the code that applied to remained.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
fs/crypto/Makefile | 3 +-
fs/crypto/bio.c | 100 --------------------------
fs/crypto/{inline_crypt.c => block.c} | 96 +++++++++++++++++++++++--
fs/crypto/fscrypt_private.h | 2 +-
include/linux/fscrypt.h | 22 +++---
5 files changed, 101 insertions(+), 122 deletions(-)
delete mode 100644 fs/crypto/bio.c
rename fs/crypto/{inline_crypt.c => block.c} (79%)
diff --git a/fs/crypto/Makefile b/fs/crypto/Makefile
index 652c7180ec6d..b03e02f0f09d 100644
--- a/fs/crypto/Makefile
+++ b/fs/crypto/Makefile
@@ -8,7 +8,6 @@ fscrypto-y := crypto.o \
keyring.o \
keysetup.o \
keysetup_v1.o \
policy.o
-fscrypto-$(CONFIG_BLOCK) += bio.o
-fscrypto-$(CONFIG_FS_ENCRYPTION_INLINE_CRYPT) += inline_crypt.o
+fscrypto-$(CONFIG_BLOCK) += block.o
diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c
deleted file mode 100644
index db095258cfca..000000000000
--- a/fs/crypto/bio.c
+++ /dev/null
@@ -1,100 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Utility functions for file contents encryption/decryption on
- * block device-based filesystems.
- *
- * Copyright (C) 2015, Google, Inc.
- * Copyright (C) 2015, Motorola Mobility
- */
-
-#include <linux/bio.h>
-#include <linux/export.h>
-#include <linux/module.h>
-#include <linux/namei.h>
-#include <linux/pagemap.h>
-
-#include "fscrypt_private.h"
-
-struct fscrypt_zero_done {
- atomic_t pending;
- blk_status_t status;
- struct completion done;
-};
-
-static void fscrypt_zeroout_range_done(struct fscrypt_zero_done *done)
-{
- if (atomic_dec_and_test(&done->pending))
- complete(&done->done);
-}
-
-static void fscrypt_zeroout_range_end_io(struct bio *bio)
-{
- struct fscrypt_zero_done *done = bio->bi_private;
-
- if (bio->bi_status)
- cmpxchg(&done->status, 0, bio->bi_status);
- fscrypt_zeroout_range_done(done);
- bio_put(bio);
-}
-
-/**
- * fscrypt_zeroout_range() - zero out a range of blocks in an encrypted file
- * @inode: the file's inode
- * @pos: the first file position (in bytes) to zero out
- * @sector: the first sector to zero out
- * @len: bytes to zero out
- *
- * Zero out filesystem blocks in an encrypted regular file on-disk, i.e. write
- * ciphertext blocks which decrypt to the all-zeroes block. The blocks must be
- * both logically and physically contiguous. It's also assumed that the
- * filesystem only uses a single block device, ->s_bdev. @len must be a
- * multiple of the file system logical block size.
- *
- * Note that since each block uses a different IV, this involves writing a
- * different ciphertext to each block; we can't simply reuse the same one.
- *
- * Return: 0 on success; -errno on failure.
- */
-int fscrypt_zeroout_range(const struct inode *inode, loff_t pos,
- sector_t sector, u64 len)
-{
- struct fscrypt_zero_done done = {
- .pending = ATOMIC_INIT(1),
- .done = COMPLETION_INITIALIZER_ONSTACK(done.done),
- };
-
- if (len == 0)
- return 0;
-
- do {
- struct bio *bio;
- unsigned int n;
-
- bio = bio_alloc(inode->i_sb->s_bdev, BIO_MAX_VECS, REQ_OP_WRITE,
- GFP_NOFS);
- bio->bi_iter.bi_sector = sector;
- bio->bi_private = &done;
- bio->bi_end_io = fscrypt_zeroout_range_end_io;
- fscrypt_set_bio_crypt_ctx(bio, inode, pos, GFP_NOFS);
-
- for (n = 0; n < BIO_MAX_VECS; n++) {
- unsigned int bytes_this_page = min(len, PAGE_SIZE);
-
- __bio_add_page(bio, ZERO_PAGE(0), bytes_this_page, 0);
- len -= bytes_this_page;
- pos += bytes_this_page;
- sector += (bytes_this_page >> SECTOR_SHIFT);
- if (!len || !fscrypt_mergeable_bio(bio, inode, pos))
- break;
- }
-
- atomic_inc(&done.pending);
- blk_crypto_submit_bio(bio);
- } while (len);
-
- fscrypt_zeroout_range_done(&done);
-
- wait_for_completion(&done.done);
- return blk_status_to_errno(done.status);
-}
-EXPORT_SYMBOL(fscrypt_zeroout_range);
diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/block.c
similarity index 79%
rename from fs/crypto/inline_crypt.c
rename to fs/crypto/block.c
index 3c3a46c5af42..60e687da7760 100644
--- a/fs/crypto/inline_crypt.c
+++ b/fs/crypto/block.c
@@ -1,22 +1,22 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Inline encryption support for fscrypt
+ * File contents en/decryption on block-based filesystems
*
* Copyright 2019 Google LLC
*/
/*
- * With "inline encryption", the block layer handles the decryption/encryption
- * as part of the bio, instead of the filesystem doing the crypto itself via
- * crypto API. See Documentation/block/inline-encryption.rst. fscrypt still
- * provides the key and IV to use.
+ * This file implements fscrypt's file contents en/decryption using blk-crypto
+ * (Documentation/block/inline-encryption.rst). fscrypt assigns a bio_crypt_ctx
+ * with a key and IV to each bio, and the block layer does the en/decryption.
+ *
+ * This file's exported functions are called only by block-based filesystems.
*/
#include <linux/blk-crypto.h>
#include <linux/blkdev.h>
-#include <linux/buffer_head.h>
#include <linux/export.h>
#include <linux/sched/mm.h>
#include <linux/slab.h>
#include <linux/uio.h>
@@ -338,5 +338,89 @@ u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk, u64 nr_blocks)
dun = ci->ci_hashed_ino + lblk;
return min_t(u64, nr_blocks, (u64)U32_MAX + 1 - dun);
}
EXPORT_SYMBOL_GPL(fscrypt_limit_io_blocks);
+
+struct fscrypt_zero_done {
+ atomic_t pending;
+ blk_status_t status;
+ struct completion done;
+};
+
+static void fscrypt_zeroout_range_done(struct fscrypt_zero_done *done)
+{
+ if (atomic_dec_and_test(&done->pending))
+ complete(&done->done);
+}
+
+static void fscrypt_zeroout_range_end_io(struct bio *bio)
+{
+ struct fscrypt_zero_done *done = bio->bi_private;
+
+ if (bio->bi_status)
+ cmpxchg(&done->status, 0, bio->bi_status);
+ fscrypt_zeroout_range_done(done);
+ bio_put(bio);
+}
+
+/**
+ * fscrypt_zeroout_range() - zero out a range of blocks in an encrypted file
+ * @inode: the file's inode
+ * @pos: the first file position (in bytes) to zero out
+ * @sector: the first sector to zero out
+ * @len: bytes to zero out
+ *
+ * Zero out filesystem blocks in an encrypted regular file on-disk, i.e. write
+ * ciphertext blocks which decrypt to the all-zeroes block. The blocks must be
+ * both logically and physically contiguous. It's also assumed that the
+ * filesystem only uses a single block device, ->s_bdev. @len must be a
+ * multiple of the file system logical block size.
+ *
+ * Note that since each block uses a different IV, this involves writing a
+ * different ciphertext to each block; we can't simply reuse the same one.
+ *
+ * Return: 0 on success; -errno on failure.
+ */
+int fscrypt_zeroout_range(const struct inode *inode, loff_t pos,
+ sector_t sector, u64 len)
+{
+ struct fscrypt_zero_done done = {
+ .pending = ATOMIC_INIT(1),
+ .done = COMPLETION_INITIALIZER_ONSTACK(done.done),
+ };
+
+ if (len == 0)
+ return 0;
+
+ do {
+ struct bio *bio;
+ unsigned int n;
+
+ bio = bio_alloc(inode->i_sb->s_bdev, BIO_MAX_VECS, REQ_OP_WRITE,
+ GFP_NOFS);
+ bio->bi_iter.bi_sector = sector;
+ bio->bi_private = &done;
+ bio->bi_end_io = fscrypt_zeroout_range_end_io;
+ fscrypt_set_bio_crypt_ctx(bio, inode, pos, GFP_NOFS);
+
+ for (n = 0; n < BIO_MAX_VECS; n++) {
+ unsigned int bytes_this_page = min(len, PAGE_SIZE);
+
+ __bio_add_page(bio, ZERO_PAGE(0), bytes_this_page, 0);
+ len -= bytes_this_page;
+ pos += bytes_this_page;
+ sector += (bytes_this_page >> SECTOR_SHIFT);
+ if (!len || !fscrypt_mergeable_bio(bio, inode, pos))
+ break;
+ }
+
+ atomic_inc(&done.pending);
+ blk_crypto_submit_bio(bio);
+ } while (len);
+
+ fscrypt_zeroout_range_done(&done);
+
+ wait_for_completion(&done.done);
+ return blk_status_to_errno(done.status);
+}
+EXPORT_SYMBOL(fscrypt_zeroout_range);
diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h
index da9040407d4a..74329e0953d1 100644
--- a/fs/crypto/fscrypt_private.h
+++ b/fs/crypto/fscrypt_private.h
@@ -393,11 +393,11 @@ void fscrypt_init_hkdf(struct hmac_sha512_key *hkdf, const u8 *master_key,
void fscrypt_hkdf_expand(const struct hmac_sha512_key *hkdf, u8 context,
const u8 *info, unsigned int infolen,
u8 *okm, unsigned int okmlen);
-/* inline_crypt.c */
+/* block.c */
#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT
static inline bool
fscrypt_using_inline_encryption(const struct fscrypt_inode_info *ci)
{
const struct inode *inode = ci->ci_inode;
diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h
index acf5b28eb9d7..52ff014aeae6 100644
--- a/include/linux/fscrypt.h
+++ b/include/linux/fscrypt.h
@@ -444,14 +444,10 @@ int fscrypt_fname_disk_to_usr(const struct inode *inode,
struct fscrypt_str *oname);
bool fscrypt_match_name(const struct fscrypt_name *fname,
const u8 *de_name, u32 de_name_len);
u64 fscrypt_fname_siphash(const struct inode *dir, const struct qstr *name);
-/* bio.c */
-int fscrypt_zeroout_range(const struct inode *inode, loff_t pos,
- sector_t sector, u64 len);
-
/* hooks.c */
int fscrypt_file_open(struct inode *inode, struct file *filp);
int __fscrypt_prepare_link(struct inode *inode, struct inode *dir,
struct dentry *dentry);
int __fscrypt_prepare_rename(struct inode *old_dir, struct dentry *old_dentry,
@@ -735,18 +731,10 @@ static inline int fscrypt_d_revalidate(struct inode *dir, const struct qstr *nam
struct dentry *dentry, unsigned int flags)
{
return 1;
}
-/* bio.c */
-
-static inline int fscrypt_zeroout_range(const struct inode *inode, loff_t pos,
- sector_t sector, u64 len)
-{
- return -EOPNOTSUPP;
-}
-
/* hooks.c */
static inline int fscrypt_file_open(struct inode *inode, struct file *filp)
{
if (IS_ENCRYPTED(inode))
@@ -842,20 +830,22 @@ static inline void fscrypt_set_ops(struct super_block *sb,
{
}
#endif /* !CONFIG_FS_ENCRYPTION */
-/* inline_crypt.c */
+/* block.c */
#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT
void fscrypt_set_bio_crypt_ctx(struct bio *bio, const struct inode *inode,
loff_t pos, gfp_t gfp_mask);
bool fscrypt_mergeable_bio(struct bio *bio, const struct inode *inode,
loff_t pos);
u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk, u64 nr_blocks);
+int fscrypt_zeroout_range(const struct inode *inode, loff_t pos,
+ sector_t sector, u64 len);
#else /* CONFIG_FS_ENCRYPTION_INLINE_CRYPT */
static inline void fscrypt_set_bio_crypt_ctx(struct bio *bio,
const struct inode *inode,
@@ -871,10 +861,16 @@ static inline bool fscrypt_mergeable_bio(struct bio *bio,
static inline u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk,
u64 nr_blocks)
{
return nr_blocks;
}
+
+static inline int fscrypt_zeroout_range(const struct inode *inode, loff_t pos,
+ sector_t sector, u64 len)
+{
+ return -EOPNOTSUPP;
+}
#endif /* !CONFIG_FS_ENCRYPTION_INLINE_CRYPT */
/**
* fscrypt_has_encryption_key() - check whether an inode has had its key set up
* @inode: the inode to check
--
2.54.0
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 16/16] fscrypt: Add safety checks to non-block-based en/decryption
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
-1 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: linux-fsdevel, linux-ext4, linux-f2fs-devel, linux-block,
Christoph Hellwig, Theodore Ts'o, Andreas Dilger, Baokun Li,
Jan Kara, Ojaswin Mujoo, Ritesh Harjani, Zhang Yi, Jaegeuk Kim,
Chao Yu, Eric Biggers
fscrypt_encrypt_pagecache_blocks(), fscrypt_encrypt_block_inplace(),
fscrypt_decrypt_block_inplace() would dereference a NULL
fscrypt_inode_info pointer if they were to be called on a file that
hasn't been opened yet or on a block-based filesystem. Since they have
the ability to report errors anyway, add WARN_ON_ONCE checks for this.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
fs/crypto/crypto.c | 61 +++++++++++++++++++++++++++++-----------------
1 file changed, 39 insertions(+), 22 deletions(-)
diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c
index 27663f4d8705..c91eda62f9a4 100644
--- a/fs/crypto/crypto.c
+++ b/fs/crypto/crypto.c
@@ -103,35 +103,44 @@ static int fscrypt_crypt_data_unit(const struct fscrypt_inode_info *ci,
fscrypt_direction_t rw, u64 index,
struct page *src_page,
struct page *dest_page, unsigned int len,
unsigned int offs)
{
- struct crypto_sync_skcipher *tfm = ci->ci_enc_key.tfm;
- SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
+ struct crypto_sync_skcipher *tfm;
union fscrypt_iv iv;
struct scatterlist dst, src;
int err;
+ if (WARN_ON_ONCE(ci == NULL)) /* File hasn't been opened yet? */
+ return -ENOKEY;
+ tfm = ci->ci_enc_key.tfm;
+ if (WARN_ON_ONCE(tfm == NULL)) /* Called on block-based filesystem? */
+ return -ENOKEY;
+
if (WARN_ON_ONCE(len <= 0))
return -EINVAL;
if (WARN_ON_ONCE(len % FSCRYPT_CONTENTS_ALIGNMENT != 0))
return -EINVAL;
fscrypt_generate_iv(&iv, index, ci);
- skcipher_request_set_callback(
- req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
- NULL, NULL);
- sg_init_table(&dst, 1);
- sg_set_page(&dst, dest_page, len, offs);
- sg_init_table(&src, 1);
- sg_set_page(&src, src_page, len, offs);
- skcipher_request_set_crypt(req, &src, &dst, len, &iv);
- if (rw == FS_DECRYPT)
- err = crypto_skcipher_decrypt(req);
- else
- err = crypto_skcipher_encrypt(req);
+ {
+ SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
+ skcipher_request_set_callback(req,
+ CRYPTO_TFM_REQ_MAY_BACKLOG |
+ CRYPTO_TFM_REQ_MAY_SLEEP,
+ NULL, NULL);
+ sg_init_table(&dst, 1);
+ sg_set_page(&dst, dest_page, len, offs);
+ sg_init_table(&src, 1);
+ sg_set_page(&src, src_page, len, offs);
+ skcipher_request_set_crypt(req, &src, &dst, len, &iv);
+ if (rw == FS_DECRYPT)
+ err = crypto_skcipher_decrypt(req);
+ else
+ err = crypto_skcipher_encrypt(req);
+ }
if (err)
fscrypt_err(ci->ci_inode,
"%scryption failed for data unit %llu: %d",
(rw == FS_DECRYPT ? "De" : "En"), index, err);
return err;
@@ -151,11 +160,11 @@ static int fscrypt_crypt_data_unit(const struct fscrypt_inode_info *ci,
*
* In the bounce page, the ciphertext data will be located at the same offset at
* which the plaintext data was located in the source page. Any other parts of
* the bounce page will be left uninitialized.
*
- * This is for use by the filesystem's ->writepages() method.
+ * This is for use by the ->writepages() method of non-block-based filesystems.
*
* The bounce page allocation is mempool-backed, so it will always succeed when
* @gfp_flags includes __GFP_DIRECT_RECLAIM, e.g. when it's GFP_NOFS. However,
* only the first page of each bio can be allocated this way. To prevent
* deadlocks, for any additional pages a mask like GFP_NOWAIT must be used.
@@ -165,18 +174,24 @@ static int fscrypt_crypt_data_unit(const struct fscrypt_inode_info *ci,
struct page *fscrypt_encrypt_pagecache_blocks(struct folio *folio,
size_t len, size_t offs, gfp_t gfp_flags)
{
const struct inode *inode = folio->mapping->host;
const struct fscrypt_inode_info *ci = fscrypt_get_inode_info_raw(inode);
- const unsigned int du_bits = ci->ci_data_unit_bits;
- const unsigned int du_size = 1U << du_bits;
+ unsigned int du_bits;
+ unsigned int du_size;
struct page *ciphertext_page;
- u64 index = ((u64)folio->index << (PAGE_SHIFT - du_bits)) +
- (offs >> du_bits);
+ u64 index;
unsigned int i;
int err;
+ if (WARN_ON_ONCE(ci == NULL)) /* File hasn't been opened yet? */
+ return ERR_PTR(-ENOKEY);
+
+ du_bits = ci->ci_data_unit_bits;
+ du_size = 1U << du_bits;
+ index = (folio_pos(folio) + offs) >> du_bits;
+
VM_BUG_ON_FOLIO(folio_test_large(folio), folio);
if (WARN_ON_ONCE(!folio_test_locked(folio)))
return ERR_PTR(-EINVAL);
if (WARN_ON_ONCE(len <= 0 || !IS_ALIGNED(len | offs, du_size)))
@@ -213,11 +228,12 @@ EXPORT_SYMBOL(fscrypt_encrypt_pagecache_blocks);
*
* Encrypt a possibly-compressed filesystem block that is located in an
* arbitrary page, not necessarily in the original pagecache page. The @inode
* and @lblk_num must be specified, as they can't be determined from @page.
*
- * This is not compatible with fscrypt_operations::supports_subblock_data_units.
+ * This function only supports non-block-based filesystems that don't support
+ * sub-block data units (as indicated by the fscrypt_operations fields).
*
* Return: 0 on success; -errno on failure
*/
int fscrypt_encrypt_block_inplace(const struct inode *inode, struct page *page,
unsigned int len, unsigned int offs,
@@ -243,11 +259,12 @@ EXPORT_SYMBOL(fscrypt_encrypt_block_inplace);
*
* Decrypt a possibly-compressed filesystem block that is located in an
* arbitrary page, not necessarily in the original pagecache page. The @inode
* and @lblk_num must be specified, as they can't be determined from @page.
*
- * This is not compatible with fscrypt_operations::supports_subblock_data_units.
+ * This function only supports non-block-based filesystems that don't support
+ * sub-block data units (as indicated by the fscrypt_operations fields).
*
* Return: 0 on success; -errno on failure
*/
int fscrypt_decrypt_block_inplace(const struct inode *inode, struct page *page,
unsigned int len, unsigned int offs,
@@ -273,11 +290,11 @@ EXPORT_SYMBOL(fscrypt_decrypt_block_inplace);
int fscrypt_initialize(struct super_block *sb)
{
mempool_t *pool;
/* pairs with smp_store_release() below */
- if (likely(smp_load_acquire(&fscrypt_bounce_page_pool)))
+ if (smp_load_acquire(&fscrypt_bounce_page_pool))
return 0;
/* No need to allocate a bounce page pool if this FS won't use it. */
if (!sb->s_cop->needs_bounce_pages)
return 0;
--
2.54.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [f2fs-dev] [PATCH 16/16] fscrypt: Add safety checks to non-block-based en/decryption
@ 2026-06-24 5:03 ` Eric Biggers via Linux-f2fs-devel
0 siblings, 0 replies; 34+ messages in thread
From: Eric Biggers via Linux-f2fs-devel @ 2026-06-24 5:03 UTC (permalink / raw)
To: linux-fscrypt
Cc: Ritesh Harjani, Theodore Ts'o, Zhang Yi, linux-f2fs-devel,
linux-block, Andreas Dilger, Ojaswin Mujoo, Baokun Li,
Jaegeuk Kim, linux-fsdevel, Jan Kara, linux-ext4,
Christoph Hellwig, Eric Biggers
fscrypt_encrypt_pagecache_blocks(), fscrypt_encrypt_block_inplace(),
fscrypt_decrypt_block_inplace() would dereference a NULL
fscrypt_inode_info pointer if they were to be called on a file that
hasn't been opened yet or on a block-based filesystem. Since they have
the ability to report errors anyway, add WARN_ON_ONCE checks for this.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
fs/crypto/crypto.c | 61 +++++++++++++++++++++++++++++-----------------
1 file changed, 39 insertions(+), 22 deletions(-)
diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c
index 27663f4d8705..c91eda62f9a4 100644
--- a/fs/crypto/crypto.c
+++ b/fs/crypto/crypto.c
@@ -103,35 +103,44 @@ static int fscrypt_crypt_data_unit(const struct fscrypt_inode_info *ci,
fscrypt_direction_t rw, u64 index,
struct page *src_page,
struct page *dest_page, unsigned int len,
unsigned int offs)
{
- struct crypto_sync_skcipher *tfm = ci->ci_enc_key.tfm;
- SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
+ struct crypto_sync_skcipher *tfm;
union fscrypt_iv iv;
struct scatterlist dst, src;
int err;
+ if (WARN_ON_ONCE(ci == NULL)) /* File hasn't been opened yet? */
+ return -ENOKEY;
+ tfm = ci->ci_enc_key.tfm;
+ if (WARN_ON_ONCE(tfm == NULL)) /* Called on block-based filesystem? */
+ return -ENOKEY;
+
if (WARN_ON_ONCE(len <= 0))
return -EINVAL;
if (WARN_ON_ONCE(len % FSCRYPT_CONTENTS_ALIGNMENT != 0))
return -EINVAL;
fscrypt_generate_iv(&iv, index, ci);
- skcipher_request_set_callback(
- req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
- NULL, NULL);
- sg_init_table(&dst, 1);
- sg_set_page(&dst, dest_page, len, offs);
- sg_init_table(&src, 1);
- sg_set_page(&src, src_page, len, offs);
- skcipher_request_set_crypt(req, &src, &dst, len, &iv);
- if (rw == FS_DECRYPT)
- err = crypto_skcipher_decrypt(req);
- else
- err = crypto_skcipher_encrypt(req);
+ {
+ SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
+ skcipher_request_set_callback(req,
+ CRYPTO_TFM_REQ_MAY_BACKLOG |
+ CRYPTO_TFM_REQ_MAY_SLEEP,
+ NULL, NULL);
+ sg_init_table(&dst, 1);
+ sg_set_page(&dst, dest_page, len, offs);
+ sg_init_table(&src, 1);
+ sg_set_page(&src, src_page, len, offs);
+ skcipher_request_set_crypt(req, &src, &dst, len, &iv);
+ if (rw == FS_DECRYPT)
+ err = crypto_skcipher_decrypt(req);
+ else
+ err = crypto_skcipher_encrypt(req);
+ }
if (err)
fscrypt_err(ci->ci_inode,
"%scryption failed for data unit %llu: %d",
(rw == FS_DECRYPT ? "De" : "En"), index, err);
return err;
@@ -151,11 +160,11 @@ static int fscrypt_crypt_data_unit(const struct fscrypt_inode_info *ci,
*
* In the bounce page, the ciphertext data will be located at the same offset at
* which the plaintext data was located in the source page. Any other parts of
* the bounce page will be left uninitialized.
*
- * This is for use by the filesystem's ->writepages() method.
+ * This is for use by the ->writepages() method of non-block-based filesystems.
*
* The bounce page allocation is mempool-backed, so it will always succeed when
* @gfp_flags includes __GFP_DIRECT_RECLAIM, e.g. when it's GFP_NOFS. However,
* only the first page of each bio can be allocated this way. To prevent
* deadlocks, for any additional pages a mask like GFP_NOWAIT must be used.
@@ -165,18 +174,24 @@ static int fscrypt_crypt_data_unit(const struct fscrypt_inode_info *ci,
struct page *fscrypt_encrypt_pagecache_blocks(struct folio *folio,
size_t len, size_t offs, gfp_t gfp_flags)
{
const struct inode *inode = folio->mapping->host;
const struct fscrypt_inode_info *ci = fscrypt_get_inode_info_raw(inode);
- const unsigned int du_bits = ci->ci_data_unit_bits;
- const unsigned int du_size = 1U << du_bits;
+ unsigned int du_bits;
+ unsigned int du_size;
struct page *ciphertext_page;
- u64 index = ((u64)folio->index << (PAGE_SHIFT - du_bits)) +
- (offs >> du_bits);
+ u64 index;
unsigned int i;
int err;
+ if (WARN_ON_ONCE(ci == NULL)) /* File hasn't been opened yet? */
+ return ERR_PTR(-ENOKEY);
+
+ du_bits = ci->ci_data_unit_bits;
+ du_size = 1U << du_bits;
+ index = (folio_pos(folio) + offs) >> du_bits;
+
VM_BUG_ON_FOLIO(folio_test_large(folio), folio);
if (WARN_ON_ONCE(!folio_test_locked(folio)))
return ERR_PTR(-EINVAL);
if (WARN_ON_ONCE(len <= 0 || !IS_ALIGNED(len | offs, du_size)))
@@ -213,11 +228,12 @@ EXPORT_SYMBOL(fscrypt_encrypt_pagecache_blocks);
*
* Encrypt a possibly-compressed filesystem block that is located in an
* arbitrary page, not necessarily in the original pagecache page. The @inode
* and @lblk_num must be specified, as they can't be determined from @page.
*
- * This is not compatible with fscrypt_operations::supports_subblock_data_units.
+ * This function only supports non-block-based filesystems that don't support
+ * sub-block data units (as indicated by the fscrypt_operations fields).
*
* Return: 0 on success; -errno on failure
*/
int fscrypt_encrypt_block_inplace(const struct inode *inode, struct page *page,
unsigned int len, unsigned int offs,
@@ -243,11 +259,12 @@ EXPORT_SYMBOL(fscrypt_encrypt_block_inplace);
*
* Decrypt a possibly-compressed filesystem block that is located in an
* arbitrary page, not necessarily in the original pagecache page. The @inode
* and @lblk_num must be specified, as they can't be determined from @page.
*
- * This is not compatible with fscrypt_operations::supports_subblock_data_units.
+ * This function only supports non-block-based filesystems that don't support
+ * sub-block data units (as indicated by the fscrypt_operations fields).
*
* Return: 0 on success; -errno on failure
*/
int fscrypt_decrypt_block_inplace(const struct inode *inode, struct page *page,
unsigned int len, unsigned int offs,
@@ -273,11 +290,11 @@ EXPORT_SYMBOL(fscrypt_decrypt_block_inplace);
int fscrypt_initialize(struct super_block *sb)
{
mempool_t *pool;
/* pairs with smp_store_release() below */
- if (likely(smp_load_acquire(&fscrypt_bounce_page_pool)))
+ if (smp_load_acquire(&fscrypt_bounce_page_pool))
return 0;
/* No need to allocate a bounce page pool if this FS won't use it. */
if (!sb->s_cop->needs_bounce_pages)
return 0;
--
2.54.0
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply related [flat|nested] 34+ messages in thread
end of thread, other threads:[~2026-06-24 5:06 UTC | newest]
Thread overview: 34+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-24 5:03 [PATCH 00/16] fscrypt: Standardize on blk-crypto Eric Biggers
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-06-24 5:03 ` [PATCH 01/16] blk-crypto: Simplify check for fallback support Eric Biggers
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-06-24 5:03 ` [PATCH 02/16] blk-crypto: Fold __blk_crypto_cfg_supported() into its caller Eric Biggers
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-06-24 5:03 ` [PATCH 03/16] blk-crypto: Allow control over whether hardware is used Eric Biggers
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-06-24 5:03 ` [PATCH 04/16] fscrypt: Fully disallow IV_INO_LBLK_32 with s_blocksize != PAGE_SIZE Eric Biggers
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-06-24 5:03 ` [PATCH 05/16] fscrypt: Always use blk-crypto for contents on block-based filesystems Eric Biggers
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-06-24 5:03 ` [PATCH 06/16] ext4: Remove fs-layer file contents en/decryption code Eric Biggers
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-06-24 5:03 ` [PATCH 07/16] ext4: Make ext4_bio_write_folio() return void Eric Biggers
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-06-24 5:03 ` [PATCH 08/16] ext4: Further de-generalize the bio postprocessing code Eric Biggers
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-06-24 5:03 ` [PATCH 09/16] f2fs: Remove fs-layer file contents en/decryption code Eric Biggers
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-06-24 5:03 ` [PATCH 10/16] fs/buffer: Remove fs-layer decryption code Eric Biggers
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-06-24 5:03 ` [PATCH 11/16] fscrypt: Replace calls to fscrypt_inode_uses_inline_crypto() Eric Biggers
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-06-24 5:03 ` [PATCH 12/16] fscrypt: Remove fscrypt_dio_supported() Eric Biggers
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-06-24 5:03 ` [PATCH 13/16] fscrypt: Remove fs-layer zeroout code Eric Biggers
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-06-24 5:03 ` [PATCH 14/16] fscrypt: Remove unused functions and workqueue Eric Biggers
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-06-24 5:03 ` [PATCH 15/16] fscrypt: Merge bio.c and inline_crypt.c into block.c Eric Biggers
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-06-24 5:03 ` [PATCH 16/16] fscrypt: Add safety checks to non-block-based en/decryption Eric Biggers
2026-06-24 5:03 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.