From: Christoph Hellwig <hch@lst.de>
To: Jens Axboe <axboe@kernel.dk>, Christian Brauner <brauner@kernel.org>
Cc: "Darrick J. Wong" <djwong@kernel.org>,
Carlos Maiolino <cem@kernel.org>,
"Martin K. Petersen" <martin.petersen@oracle.com>,
Anuj Gupta <anuj20.g@samsung.com>,
Kanchan Joshi <joshi.k@samsung.com>,
linux-block@vger.kernel.org, nvdimm@lists.linux.dev,
linux-fsdevel@vger.kernel.org, linux-xfs@vger.kernel.org
Subject: [PATCH 14/15] iomap: support T10 protection information
Date: Wed, 18 Feb 2026 07:12:08 +0100 [thread overview]
Message-ID: <20260218061238.3317841-15-hch@lst.de> (raw)
In-Reply-To: <20260218061238.3317841-1-hch@lst.de>
Add support for generating / verifying protection information in iomap.
This is done by hooking into the bio submission and then using the
generic PI helpers. Compared to just using the block layer auto PI
this extends the protection envelope and also prepares for eventually
passing through PI from userspace at least for direct I/O.
To generate or verify PI, the file system needs to set the
IOMAP_F_INTEGRITY flag on the iomap for the request, and ensure the
ioends are used for all integrity I/O. Additionally the file system
must defer read I/O completions to user context so that the guard
tag validation isn't run from interrupt context.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
Tested-by: Anuj Gupta <anuj20.g@samsung.com>
---
fs/iomap/bio.c | 24 +++++++++++++++++++++---
fs/iomap/direct-io.c | 15 ++++++++++++++-
fs/iomap/internal.h | 13 +++++++++++++
fs/iomap/ioend.c | 20 ++++++++++++++++++--
include/linux/iomap.h | 7 +++++++
5 files changed, 73 insertions(+), 6 deletions(-)
diff --git a/fs/iomap/bio.c b/fs/iomap/bio.c
index b4de67bdd513..f989ffcaac96 100644
--- a/fs/iomap/bio.c
+++ b/fs/iomap/bio.c
@@ -3,6 +3,7 @@
* Copyright (C) 2010 Red Hat, Inc.
* Copyright (C) 2016-2023 Christoph Hellwig.
*/
+#include <linux/bio-integrity.h>
#include <linux/iomap.h>
#include <linux/pagemap.h>
#include "internal.h"
@@ -17,6 +18,8 @@ static u32 __iomap_read_end_io(struct bio *bio, int error)
iomap_finish_folio_read(fi.folio, fi.offset, fi.length, error);
folio_count++;
}
+ if (bio_integrity(bio))
+ fs_bio_integrity_free(bio);
bio_put(bio);
return folio_count;
}
@@ -34,7 +37,11 @@ u32 iomap_finish_ioend_buffered_read(struct iomap_ioend *ioend)
static void iomap_bio_submit_read(const struct iomap_iter *iter,
struct iomap_read_folio_ctx *ctx)
{
- submit_bio(ctx->read_ctx);
+ struct bio *bio = ctx->read_ctx;
+
+ if (iter->iomap.flags & IOMAP_F_INTEGRITY)
+ fs_bio_integrity_alloc(bio);
+ submit_bio(bio);
}
static struct bio_set *iomap_read_bio_set(struct iomap_read_folio_ctx *ctx)
@@ -91,6 +98,7 @@ int iomap_bio_read_folio_range(const struct iomap_iter *iter,
if (!bio ||
bio_end_sector(bio) != iomap_sector(&iter->iomap, iter->pos) ||
+ bio->bi_iter.bi_size > iomap_max_bio_size(&iter->iomap) - plen ||
!bio_add_folio(bio, folio, plen, offset_in_folio(folio, iter->pos)))
iomap_read_alloc_bio(iter, ctx, plen);
return 0;
@@ -107,11 +115,21 @@ int iomap_bio_read_folio_range_sync(const struct iomap_iter *iter,
struct folio *folio, loff_t pos, size_t len)
{
const struct iomap *srcmap = iomap_iter_srcmap(iter);
+ sector_t sector = iomap_sector(srcmap, pos);
struct bio_vec bvec;
struct bio bio;
+ int error;
bio_init(&bio, srcmap->bdev, &bvec, 1, REQ_OP_READ);
- bio.bi_iter.bi_sector = iomap_sector(srcmap, pos);
+ bio.bi_iter.bi_sector = sector;
bio_add_folio_nofail(&bio, folio, len, offset_in_folio(folio, pos));
- return submit_bio_wait(&bio);
+ if (srcmap->flags & IOMAP_F_INTEGRITY)
+ fs_bio_integrity_alloc(&bio);
+ error = submit_bio_wait(&bio);
+ if (srcmap->flags & IOMAP_F_INTEGRITY) {
+ if (!error)
+ error = fs_bio_integrity_verify(&bio, sector, len);
+ fs_bio_integrity_free(&bio);
+ }
+ return error;
}
diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c
index 2ad7c70a4ccb..b0172da3be49 100644
--- a/fs/iomap/direct-io.c
+++ b/fs/iomap/direct-io.c
@@ -3,6 +3,7 @@
* Copyright (C) 2010 Red Hat, Inc.
* Copyright (c) 2016-2025 Christoph Hellwig.
*/
+#include <linux/bio-integrity.h>
#include <linux/blk-crypto.h>
#include <linux/fscrypt.h>
#include <linux/pagemap.h>
@@ -227,6 +228,9 @@ static void __iomap_dio_bio_end_io(struct bio *bio, bool inline_completion)
{
struct iomap_dio *dio = bio->bi_private;
+ if (bio_integrity(bio))
+ fs_bio_integrity_free(bio);
+
if (dio->flags & IOMAP_DIO_BOUNCE) {
bio_iov_iter_unbounce(bio, !!dio->error,
dio->flags & IOMAP_DIO_USER_BACKED);
@@ -337,8 +341,10 @@ static ssize_t iomap_dio_bio_iter_one(struct iomap_iter *iter,
bio->bi_private = dio;
bio->bi_end_io = iomap_dio_bio_end_io;
+
if (dio->flags & IOMAP_DIO_BOUNCE)
- ret = bio_iov_iter_bounce(bio, dio->submit.iter, BIO_MAX_SIZE);
+ ret = bio_iov_iter_bounce(bio, dio->submit.iter,
+ iomap_max_bio_size(&iter->iomap));
else
ret = bio_iov_iter_get_pages(bio, dio->submit.iter,
alignment - 1);
@@ -355,6 +361,13 @@ static ssize_t iomap_dio_bio_iter_one(struct iomap_iter *iter,
goto out_put_bio;
}
+ if (iter->iomap.flags & IOMAP_F_INTEGRITY) {
+ if (dio->flags & IOMAP_DIO_WRITE)
+ fs_bio_integrity_generate(bio);
+ else
+ fs_bio_integrity_alloc(bio);
+ }
+
if (dio->flags & IOMAP_DIO_WRITE)
task_io_account_write(ret);
else if ((dio->flags & IOMAP_DIO_USER_BACKED) &&
diff --git a/fs/iomap/internal.h b/fs/iomap/internal.h
index b39dbc17e3f0..74e898b196dc 100644
--- a/fs/iomap/internal.h
+++ b/fs/iomap/internal.h
@@ -4,6 +4,19 @@
#define IOEND_BATCH_SIZE 4096
+/*
+ * Normally we can build bios as big as the data structure supports.
+ *
+ * But for integrity protected I/O we need to respect the maximum size of the
+ * single contiguous allocation for the integrity buffer.
+ */
+static inline size_t iomap_max_bio_size(const struct iomap *iomap)
+{
+ if (iomap->flags & IOMAP_F_INTEGRITY)
+ return max_integrity_io_size(bdev_limits(iomap->bdev));
+ return BIO_MAX_SIZE;
+}
+
u32 iomap_finish_ioend_buffered_read(struct iomap_ioend *ioend);
u32 iomap_finish_ioend_direct(struct iomap_ioend *ioend);
diff --git a/fs/iomap/ioend.c b/fs/iomap/ioend.c
index c6b6cd0f2fdd..bf251d206f50 100644
--- a/fs/iomap/ioend.c
+++ b/fs/iomap/ioend.c
@@ -2,6 +2,7 @@
/*
* Copyright (c) 2016-2025 Christoph Hellwig.
*/
+#include <linux/bio-integrity.h>
#include <linux/iomap.h>
#include <linux/list_sort.h>
#include <linux/pagemap.h>
@@ -65,6 +66,8 @@ static u32 iomap_finish_ioend_buffered_write(struct iomap_ioend *ioend)
folio_count++;
}
+ if (bio_integrity(bio))
+ fs_bio_integrity_free(bio);
bio_put(bio); /* frees the ioend */
return folio_count;
}
@@ -98,6 +101,8 @@ int iomap_ioend_writeback_submit(struct iomap_writepage_ctx *wpc, int error)
return error;
}
+ if (wpc->iomap.flags & IOMAP_F_INTEGRITY)
+ fs_bio_integrity_generate(&ioend->io_bio);
submit_bio(&ioend->io_bio);
return 0;
}
@@ -119,10 +124,13 @@ static struct iomap_ioend *iomap_alloc_ioend(struct iomap_writepage_ctx *wpc,
}
static bool iomap_can_add_to_ioend(struct iomap_writepage_ctx *wpc, loff_t pos,
- u16 ioend_flags)
+ unsigned int map_len, u16 ioend_flags)
{
struct iomap_ioend *ioend = wpc->wb_ctx;
+ if (ioend->io_bio.bi_iter.bi_size >
+ iomap_max_bio_size(&wpc->iomap) - map_len)
+ return false;
if (ioend_flags & IOMAP_IOEND_BOUNDARY)
return false;
if ((ioend_flags & IOMAP_IOEND_NOMERGE_FLAGS) !=
@@ -187,7 +195,7 @@ ssize_t iomap_add_to_ioend(struct iomap_writepage_ctx *wpc, struct folio *folio,
if (pos == wpc->iomap.offset && (wpc->iomap.flags & IOMAP_F_BOUNDARY))
ioend_flags |= IOMAP_IOEND_BOUNDARY;
- if (!ioend || !iomap_can_add_to_ioend(wpc, pos, ioend_flags)) {
+ if (!ioend || !iomap_can_add_to_ioend(wpc, pos, map_len, ioend_flags)) {
new_ioend:
if (ioend) {
error = wpc->ops->writeback_submit(wpc, 0);
@@ -264,6 +272,14 @@ static u32 iomap_finish_ioend(struct iomap_ioend *ioend, int error)
if (!atomic_dec_and_test(&ioend->io_remaining))
return 0;
+
+ if (!ioend->io_error &&
+ bio_integrity(&ioend->io_bio) &&
+ bio_op(&ioend->io_bio) == REQ_OP_READ) {
+ ioend->io_error = fs_bio_integrity_verify(&ioend->io_bio,
+ ioend->io_sector, ioend->io_size);
+ }
+
if (ioend->io_flags & IOMAP_IOEND_DIRECT)
return iomap_finish_ioend_direct(ioend);
if (bio_op(&ioend->io_bio) == REQ_OP_READ)
diff --git a/include/linux/iomap.h b/include/linux/iomap.h
index 387a1174522f..531f9ebdeeae 100644
--- a/include/linux/iomap.h
+++ b/include/linux/iomap.h
@@ -65,6 +65,8 @@ struct vm_fault;
*
* IOMAP_F_ATOMIC_BIO indicates that (write) I/O will be issued as an atomic
* bio, i.e. set REQ_ATOMIC.
+ *
+ * IOMAP_F_INTEGRITY indicates that the filesystems handles integrity metadata.
*/
#define IOMAP_F_NEW (1U << 0)
#define IOMAP_F_DIRTY (1U << 1)
@@ -79,6 +81,11 @@ struct vm_fault;
#define IOMAP_F_BOUNDARY (1U << 6)
#define IOMAP_F_ANON_WRITE (1U << 7)
#define IOMAP_F_ATOMIC_BIO (1U << 8)
+#ifdef CONFIG_BLK_DEV_INTEGRITY
+#define IOMAP_F_INTEGRITY (1U << 9)
+#else
+#define IOMAP_F_INTEGRITY 0
+#endif /* CONFIG_BLK_DEV_INTEGRITY */
/*
* Flag reserved for file system specific usage
--
2.47.3
next prev parent reply other threads:[~2026-02-18 6:13 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-18 6:11 support file system generated / verified integrity information v3 Christoph Hellwig
2026-02-18 6:11 ` [PATCH 01/15] block: factor out a bio_integrity_action helper Christoph Hellwig
2026-02-18 6:11 ` [PATCH 02/15] block: factor out a bio_integrity_setup_default helper Christoph Hellwig
2026-02-18 6:11 ` [PATCH 03/15] block: add a bdev_has_integrity_csum helper Christoph Hellwig
2026-02-18 6:11 ` [PATCH 04/15] block: prepare generation / verification helpers for fs usage Christoph Hellwig
2026-02-18 6:11 ` [PATCH 05/15] block: make max_integrity_io_size public Christoph Hellwig
2026-02-18 6:12 ` [PATCH 06/15] block: add fs_bio_integrity helpers Christoph Hellwig
2026-02-18 6:12 ` [PATCH 07/15] block: pass a maxlen argument to bio_iov_iter_bounce Christoph Hellwig
2026-02-18 10:52 ` Kanchan Joshi
2026-02-18 6:12 ` [PATCH 08/15] iomap: refactor iomap_bio_read_folio_range Christoph Hellwig
2026-02-18 6:12 ` [PATCH 09/15] iomap: pass the iomap_iter to ->submit_read Christoph Hellwig
2026-02-18 6:12 ` [PATCH 10/15] iomap: only call into ->submit_read when there is a read_ctx Christoph Hellwig
2026-02-19 7:17 ` Christoph Hellwig
2026-02-18 6:12 ` [PATCH 11/15] iomap: allow file systems to hook into buffered read bio submission Christoph Hellwig
2026-02-18 6:12 ` [PATCH 12/15] iomap: add a bioset pointer to iomap_read_folio_ops Christoph Hellwig
2026-02-18 6:12 ` [PATCH 13/15] iomap: support ioends for buffered reads Christoph Hellwig
2026-02-18 6:12 ` Christoph Hellwig [this message]
2026-02-18 6:12 ` [PATCH 15/15] xfs: support T10 protection information Christoph Hellwig
-- strict thread matches above, loose matches on Subject: below --
2026-01-28 16:14 support file system generated / verified integrity information v2 Christoph Hellwig
2026-01-28 16:15 ` [PATCH 14/15] iomap: support T10 protection information Christoph Hellwig
2026-01-28 16:30 ` Darrick J. Wong
2026-01-21 6:43 support file system generated / verified integrity information Christoph Hellwig
2026-01-21 6:43 ` [PATCH 14/15] iomap: support T10 protection information Christoph Hellwig
2026-01-22 0:59 ` Darrick J. Wong
2026-01-22 6:03 ` Christoph Hellwig
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=20260218061238.3317841-15-hch@lst.de \
--to=hch@lst.de \
--cc=anuj20.g@samsung.com \
--cc=axboe@kernel.dk \
--cc=brauner@kernel.org \
--cc=cem@kernel.org \
--cc=djwong@kernel.org \
--cc=joshi.k@samsung.com \
--cc=linux-block@vger.kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-xfs@vger.kernel.org \
--cc=martin.petersen@oracle.com \
--cc=nvdimm@lists.linux.dev \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox