From: Eric Biggers <ebiggers@kernel.org>
To: linux-fscrypt@vger.kernel.org
Cc: linux-fsdevel@vger.kernel.org, linux-ext4@vger.kernel.org,
linux-f2fs-devel@lists.sourceforge.net,
linux-block@vger.kernel.org, Christoph Hellwig <hch@lst.de>,
Theodore Ts'o <tytso@mit.edu>,
Andreas Dilger <adilger.kernel@dilger.ca>,
Baokun Li <libaokun@linux.alibaba.com>, Jan Kara <jack@suse.cz>,
Ojaswin Mujoo <ojaswin@linux.ibm.com>,
Ritesh Harjani <ritesh.list@gmail.com>,
Zhang Yi <yi.zhang@huawei.com>, Jaegeuk Kim <jaegeuk@kernel.org>,
Chao Yu <chao@kernel.org>, Eric Biggers <ebiggers@kernel.org>
Subject: [PATCH v2 03/17] blk-crypto: Allow control over whether hardware is used
Date: Sun, 5 Jul 2026 12:45:40 -0700 [thread overview]
Message-ID: <20260705194555.75030-4-ebiggers@kernel.org> (raw)
In-Reply-To: <20260705194555.75030-1-ebiggers@kernel.org>
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, extend blk_crypto_config with a new flag
BLK_CRYPTO_CFG_ALLOW_HW.
For now it's always set. Later commits will change that.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
block/blk-crypto.c | 11 ++++++++++-
drivers/md/dm-inlinecrypt.c | 3 ++-
fs/crypto/inline_crypt.c | 4 +++-
include/linux/blk-crypto.h | 14 ++++++++++++--
4 files changed, 27 insertions(+), 5 deletions(-)
diff --git a/block/blk-crypto.c b/block/blk-crypto.c
index de60f03b4d4b..0fe6ef0eea1d 100644
--- a/block/blk-crypto.c
+++ b/block/blk-crypto.c
@@ -300,6 +300,7 @@ int __blk_crypto_rq_bio_prep(struct request *rq, struct bio *bio,
* @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
+ * @flags: BLK_CRYPTO_CFG_* flags
*
* Return: 0 on success, -errno on failure. The caller is responsible for
* zeroizing both blk_key and key_bytes when done with them.
@@ -309,7 +310,7 @@ int blk_crypto_init_key(struct blk_crypto_key *blk_key,
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, int flags)
{
const struct blk_crypto_mode *mode;
@@ -318,6 +319,9 @@ int blk_crypto_init_key(struct blk_crypto_key *blk_key,
if (crypto_mode >= ARRAY_SIZE(blk_crypto_modes))
return -EINVAL;
+ if (flags & ~BLK_CRYPTO_CFG_ALLOW_HW)
+ return -EINVAL;
+
mode = &blk_crypto_modes[crypto_mode];
switch (key_type) {
case BLK_CRYPTO_KEY_TYPE_RAW:
@@ -328,6 +332,8 @@ int blk_crypto_init_key(struct blk_crypto_key *blk_key,
if (key_size < mode->security_strength ||
key_size > BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE)
return -EINVAL;
+ if (!(flags & BLK_CRYPTO_CFG_ALLOW_HW))
+ return -EINVAL;
break;
default:
return -EINVAL;
@@ -343,6 +349,7 @@ int blk_crypto_init_key(struct blk_crypto_key *blk_key,
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.flags = flags;
blk_key->data_unit_size_bits = ilog2(data_unit_size);
blk_key->size = key_size;
memcpy(blk_key->bytes, key_bytes, key_size);
@@ -368,6 +375,8 @@ bool blk_crypto_config_supported_natively(struct block_device *bdev,
if (!profile)
return false;
+ if (!(cfg->flags & BLK_CRYPTO_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)
diff --git a/drivers/md/dm-inlinecrypt.c b/drivers/md/dm-inlinecrypt.c
index be1b4aa8f28b..35379f5c84df 100644
--- a/drivers/md/dm-inlinecrypt.c
+++ b/drivers/md/dm-inlinecrypt.c
@@ -406,7 +406,8 @@ static int inlinecrypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
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,
+ BLK_CRYPTO_CFG_ALLOW_HW);
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..aaf71f6068b0 100644
--- a/fs/crypto/inline_crypt.c
+++ b/fs/crypto/inline_crypt.c
@@ -134,6 +134,7 @@ int fscrypt_select_encryption_impl(struct fscrypt_inode_info *ci,
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.flags = BLK_CRYPTO_CFG_ALLOW_HW;
devs = fscrypt_get_devices(sb, &num_devs);
if (IS_ERR(devs))
@@ -175,7 +176,8 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
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,
+ BLK_CRYPTO_CFG_ALLOW_HW);
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..b4a7be8e95c0 100644
--- a/include/linux/blk-crypto.h
+++ b/include/linux/blk-crypto.h
@@ -68,6 +68,15 @@ enum blk_crypto_key_type {
*/
#define BLK_CRYPTO_SW_SECRET_SIZE 32
+/* Flags for blk_crypto_config::flags: */
+
+/*
+ * If set, inline encryption hardware will be used if available.
+ * If unset, CPU-based encryption will always be used (requires
+ * CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK)
+ */
+#define BLK_CRYPTO_CFG_ALLOW_HW (1 << 0)
+
/**
* struct blk_crypto_config - an inline encryption key's crypto configuration
* @crypto_mode: encryption algorithm this key is for
@@ -76,13 +85,14 @@ enum blk_crypto_key_type {
* 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
+ * @flags: BLK_CRYPTO_CFG_* flags
*/
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;
+ int flags;
};
/**
@@ -150,7 +160,7 @@ int blk_crypto_init_key(struct blk_crypto_key *blk_key,
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, int flags);
int blk_crypto_start_using_key(struct block_device *bdev,
const struct blk_crypto_key *key);
--
2.54.0
WARNING: multiple messages have this Message-ID (diff)
From: Eric Biggers via Linux-f2fs-devel <linux-f2fs-devel@lists.sourceforge.net>
To: linux-fscrypt@vger.kernel.org
Cc: Ritesh Harjani <ritesh.list@gmail.com>,
Theodore Ts'o <tytso@mit.edu>, Zhang Yi <yi.zhang@huawei.com>,
linux-f2fs-devel@lists.sourceforge.net,
linux-block@vger.kernel.org,
Andreas Dilger <adilger.kernel@dilger.ca>,
Ojaswin Mujoo <ojaswin@linux.ibm.com>,
Baokun Li <libaokun@linux.alibaba.com>,
Jaegeuk Kim <jaegeuk@kernel.org>,
linux-fsdevel@vger.kernel.org, Jan Kara <jack@suse.cz>,
linux-ext4@vger.kernel.org, Christoph Hellwig <hch@lst.de>,
Eric Biggers <ebiggers@kernel.org>
Subject: [f2fs-dev] [PATCH v2 03/17] blk-crypto: Allow control over whether hardware is used
Date: Sun, 5 Jul 2026 12:45:40 -0700 [thread overview]
Message-ID: <20260705194555.75030-4-ebiggers@kernel.org> (raw)
In-Reply-To: <20260705194555.75030-1-ebiggers@kernel.org>
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, extend blk_crypto_config with a new flag
BLK_CRYPTO_CFG_ALLOW_HW.
For now it's always set. Later commits will change that.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
block/blk-crypto.c | 11 ++++++++++-
drivers/md/dm-inlinecrypt.c | 3 ++-
fs/crypto/inline_crypt.c | 4 +++-
include/linux/blk-crypto.h | 14 ++++++++++++--
4 files changed, 27 insertions(+), 5 deletions(-)
diff --git a/block/blk-crypto.c b/block/blk-crypto.c
index de60f03b4d4b..0fe6ef0eea1d 100644
--- a/block/blk-crypto.c
+++ b/block/blk-crypto.c
@@ -300,6 +300,7 @@ int __blk_crypto_rq_bio_prep(struct request *rq, struct bio *bio,
* @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
+ * @flags: BLK_CRYPTO_CFG_* flags
*
* Return: 0 on success, -errno on failure. The caller is responsible for
* zeroizing both blk_key and key_bytes when done with them.
@@ -309,7 +310,7 @@ int blk_crypto_init_key(struct blk_crypto_key *blk_key,
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, int flags)
{
const struct blk_crypto_mode *mode;
@@ -318,6 +319,9 @@ int blk_crypto_init_key(struct blk_crypto_key *blk_key,
if (crypto_mode >= ARRAY_SIZE(blk_crypto_modes))
return -EINVAL;
+ if (flags & ~BLK_CRYPTO_CFG_ALLOW_HW)
+ return -EINVAL;
+
mode = &blk_crypto_modes[crypto_mode];
switch (key_type) {
case BLK_CRYPTO_KEY_TYPE_RAW:
@@ -328,6 +332,8 @@ int blk_crypto_init_key(struct blk_crypto_key *blk_key,
if (key_size < mode->security_strength ||
key_size > BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE)
return -EINVAL;
+ if (!(flags & BLK_CRYPTO_CFG_ALLOW_HW))
+ return -EINVAL;
break;
default:
return -EINVAL;
@@ -343,6 +349,7 @@ int blk_crypto_init_key(struct blk_crypto_key *blk_key,
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.flags = flags;
blk_key->data_unit_size_bits = ilog2(data_unit_size);
blk_key->size = key_size;
memcpy(blk_key->bytes, key_bytes, key_size);
@@ -368,6 +375,8 @@ bool blk_crypto_config_supported_natively(struct block_device *bdev,
if (!profile)
return false;
+ if (!(cfg->flags & BLK_CRYPTO_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)
diff --git a/drivers/md/dm-inlinecrypt.c b/drivers/md/dm-inlinecrypt.c
index be1b4aa8f28b..35379f5c84df 100644
--- a/drivers/md/dm-inlinecrypt.c
+++ b/drivers/md/dm-inlinecrypt.c
@@ -406,7 +406,8 @@ static int inlinecrypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
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,
+ BLK_CRYPTO_CFG_ALLOW_HW);
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..aaf71f6068b0 100644
--- a/fs/crypto/inline_crypt.c
+++ b/fs/crypto/inline_crypt.c
@@ -134,6 +134,7 @@ int fscrypt_select_encryption_impl(struct fscrypt_inode_info *ci,
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.flags = BLK_CRYPTO_CFG_ALLOW_HW;
devs = fscrypt_get_devices(sb, &num_devs);
if (IS_ERR(devs))
@@ -175,7 +176,8 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
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,
+ BLK_CRYPTO_CFG_ALLOW_HW);
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..b4a7be8e95c0 100644
--- a/include/linux/blk-crypto.h
+++ b/include/linux/blk-crypto.h
@@ -68,6 +68,15 @@ enum blk_crypto_key_type {
*/
#define BLK_CRYPTO_SW_SECRET_SIZE 32
+/* Flags for blk_crypto_config::flags: */
+
+/*
+ * If set, inline encryption hardware will be used if available.
+ * If unset, CPU-based encryption will always be used (requires
+ * CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK)
+ */
+#define BLK_CRYPTO_CFG_ALLOW_HW (1 << 0)
+
/**
* struct blk_crypto_config - an inline encryption key's crypto configuration
* @crypto_mode: encryption algorithm this key is for
@@ -76,13 +85,14 @@ enum blk_crypto_key_type {
* 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
+ * @flags: BLK_CRYPTO_CFG_* flags
*/
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;
+ int flags;
};
/**
@@ -150,7 +160,7 @@ int blk_crypto_init_key(struct blk_crypto_key *blk_key,
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, int flags);
int blk_crypto_start_using_key(struct block_device *bdev,
const struct blk_crypto_key *key);
--
2.54.0
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
next prev parent reply other threads:[~2026-07-05 19:47 UTC|newest]
Thread overview: 46+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-05 19:45 [PATCH v2 00/17] fscrypt: Standardize on blk-crypto Eric Biggers
2026-07-05 19:45 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-07-05 19:45 ` [PATCH v2 01/17] blk-crypto: Simplify check for fallback support Eric Biggers
2026-07-05 19:45 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-07-05 19:45 ` [PATCH v2 02/17] blk-crypto: Fold __blk_crypto_cfg_supported() into its caller Eric Biggers
2026-07-05 19:45 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-07-05 20:08 ` Eric Biggers
2026-07-05 20:08 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-07-05 19:45 ` Eric Biggers [this message]
2026-07-05 19:45 ` [f2fs-dev] [PATCH v2 03/17] blk-crypto: Allow control over whether hardware is used Eric Biggers via Linux-f2fs-devel
2026-07-05 20:09 ` Eric Biggers
2026-07-05 20:09 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-07-05 19:45 ` [PATCH v2 04/17] fscrypt: Fully disallow IV_INO_LBLK_32 with s_blocksize != PAGE_SIZE Eric Biggers
2026-07-05 19:45 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-07-05 20:15 ` Eric Biggers
2026-07-05 20:15 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-07-05 19:45 ` [PATCH v2 05/17] fscrypt: Always use blk-crypto for contents on block-based filesystems Eric Biggers
2026-07-05 19:45 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-07-05 19:45 ` [PATCH v2 06/17] Documentation: fscrypt: Update docs for inlinecrypt Eric Biggers
2026-07-05 19:45 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-07-05 19:45 ` [PATCH v2 07/17] ext4: Remove fs-layer file contents en/decryption code Eric Biggers
2026-07-05 19:45 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-07-05 19:45 ` [PATCH v2 08/17] ext4: Make ext4_bio_write_folio() return void Eric Biggers
2026-07-05 19:45 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-07-05 20:27 ` Eric Biggers
2026-07-05 20:27 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-07-05 19:45 ` [PATCH v2 09/17] ext4: Further de-generalize the bio postprocessing code Eric Biggers
2026-07-05 19:45 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-07-05 19:45 ` [PATCH v2 10/17] f2fs: Remove fs-layer file contents en/decryption code Eric Biggers
2026-07-05 19:45 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-07-05 19:45 ` [PATCH v2 11/17] fs/buffer: Remove fs-layer decryption code Eric Biggers
2026-07-05 19:45 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-07-05 19:45 ` [PATCH v2 12/17] fscrypt: Replace calls to fscrypt_inode_uses_inline_crypto() Eric Biggers
2026-07-05 19:45 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-07-05 19:45 ` [PATCH v2 13/17] fscrypt: Remove fscrypt_dio_supported() Eric Biggers
2026-07-05 19:45 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-07-05 20:19 ` Eric Biggers
2026-07-05 20:19 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-07-05 19:45 ` [PATCH v2 14/17] fscrypt: Remove fs-layer zeroout code Eric Biggers
2026-07-05 19:45 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-07-05 19:45 ` [PATCH v2 15/17] fscrypt: Remove unused functions and workqueue Eric Biggers
2026-07-05 19:45 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-07-05 19:45 ` [PATCH v2 16/17] fscrypt: Merge bio.c and inline_crypt.c into block.c Eric Biggers
2026-07-05 19:45 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
2026-07-05 19:45 ` [PATCH v2 17/17] fscrypt: Add safety checks to non-block-based en/decryption Eric Biggers
2026-07-05 19:45 ` [f2fs-dev] " Eric Biggers via Linux-f2fs-devel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260705194555.75030-4-ebiggers@kernel.org \
--to=ebiggers@kernel.org \
--cc=adilger.kernel@dilger.ca \
--cc=chao@kernel.org \
--cc=hch@lst.de \
--cc=jack@suse.cz \
--cc=jaegeuk@kernel.org \
--cc=libaokun@linux.alibaba.com \
--cc=linux-block@vger.kernel.org \
--cc=linux-ext4@vger.kernel.org \
--cc=linux-f2fs-devel@lists.sourceforge.net \
--cc=linux-fscrypt@vger.kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=ojaswin@linux.ibm.com \
--cc=ritesh.list@gmail.com \
--cc=tytso@mit.edu \
--cc=yi.zhang@huawei.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.