Skip to content

Commit 0b10a37

Browse files
Christoph Hellwigbrauner
authored andcommitted
iomap: support T10 protection information
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> Link: https://patch.msgid.link/20260223132021.292832-16-hch@lst.de Tested-by: Anuj Gupta <anuj20.g@samsung.com> Reviewed-by: "Darrick J. Wong" <djwong@kernel.org> Signed-off-by: Christian Brauner <brauner@kernel.org>
1 parent e8f9cf0 commit 0b10a37

5 files changed

Lines changed: 73 additions & 6 deletions

File tree

fs/iomap/bio.c

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Copyright (C) 2010 Red Hat, Inc.
44
* Copyright (C) 2016-2023 Christoph Hellwig.
55
*/
6+
#include <linux/bio-integrity.h>
67
#include <linux/iomap.h>
78
#include <linux/pagemap.h>
89
#include "internal.h"
@@ -17,6 +18,8 @@ static u32 __iomap_read_end_io(struct bio *bio, int error)
1718
iomap_finish_folio_read(fi.folio, fi.offset, fi.length, error);
1819
folio_count++;
1920
}
21+
if (bio_integrity(bio))
22+
fs_bio_integrity_free(bio);
2023
bio_put(bio);
2124
return folio_count;
2225
}
@@ -34,7 +37,11 @@ u32 iomap_finish_ioend_buffered_read(struct iomap_ioend *ioend)
3437
static void iomap_bio_submit_read(const struct iomap_iter *iter,
3538
struct iomap_read_folio_ctx *ctx)
3639
{
37-
submit_bio(ctx->read_ctx);
40+
struct bio *bio = ctx->read_ctx;
41+
42+
if (iter->iomap.flags & IOMAP_F_INTEGRITY)
43+
fs_bio_integrity_alloc(bio);
44+
submit_bio(bio);
3845
}
3946

4047
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,
9198

9299
if (!bio ||
93100
bio_end_sector(bio) != iomap_sector(&iter->iomap, iter->pos) ||
101+
bio->bi_iter.bi_size > iomap_max_bio_size(&iter->iomap) - plen ||
94102
!bio_add_folio(bio, folio, plen, offset_in_folio(folio, iter->pos)))
95103
iomap_read_alloc_bio(iter, ctx, plen);
96104
return 0;
@@ -107,11 +115,21 @@ int iomap_bio_read_folio_range_sync(const struct iomap_iter *iter,
107115
struct folio *folio, loff_t pos, size_t len)
108116
{
109117
const struct iomap *srcmap = iomap_iter_srcmap(iter);
118+
sector_t sector = iomap_sector(srcmap, pos);
110119
struct bio_vec bvec;
111120
struct bio bio;
121+
int error;
112122

113123
bio_init(&bio, srcmap->bdev, &bvec, 1, REQ_OP_READ);
114-
bio.bi_iter.bi_sector = iomap_sector(srcmap, pos);
124+
bio.bi_iter.bi_sector = sector;
115125
bio_add_folio_nofail(&bio, folio, len, offset_in_folio(folio, pos));
116-
return submit_bio_wait(&bio);
126+
if (srcmap->flags & IOMAP_F_INTEGRITY)
127+
fs_bio_integrity_alloc(&bio);
128+
error = submit_bio_wait(&bio);
129+
if (srcmap->flags & IOMAP_F_INTEGRITY) {
130+
if (!error)
131+
error = fs_bio_integrity_verify(&bio, sector, len);
132+
fs_bio_integrity_free(&bio);
133+
}
134+
return error;
117135
}

fs/iomap/direct-io.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Copyright (C) 2010 Red Hat, Inc.
44
* Copyright (c) 2016-2025 Christoph Hellwig.
55
*/
6+
#include <linux/bio-integrity.h>
67
#include <linux/blk-crypto.h>
78
#include <linux/fscrypt.h>
89
#include <linux/pagemap.h>
@@ -240,6 +241,9 @@ static void __iomap_dio_bio_end_io(struct bio *bio, bool inline_completion)
240241
{
241242
struct iomap_dio *dio = bio->bi_private;
242243

244+
if (bio_integrity(bio))
245+
fs_bio_integrity_free(bio);
246+
243247
if (dio->flags & IOMAP_DIO_BOUNCE) {
244248
bio_iov_iter_unbounce(bio, !!dio->error,
245249
dio->flags & IOMAP_DIO_USER_BACKED);
@@ -350,8 +354,10 @@ static ssize_t iomap_dio_bio_iter_one(struct iomap_iter *iter,
350354
bio->bi_private = dio;
351355
bio->bi_end_io = iomap_dio_bio_end_io;
352356

357+
353358
if (dio->flags & IOMAP_DIO_BOUNCE)
354-
ret = bio_iov_iter_bounce(bio, dio->submit.iter, BIO_MAX_SIZE);
359+
ret = bio_iov_iter_bounce(bio, dio->submit.iter,
360+
iomap_max_bio_size(&iter->iomap));
355361
else
356362
ret = bio_iov_iter_get_pages(bio, dio->submit.iter,
357363
alignment - 1);
@@ -368,6 +374,13 @@ static ssize_t iomap_dio_bio_iter_one(struct iomap_iter *iter,
368374
goto out_put_bio;
369375
}
370376

377+
if (iter->iomap.flags & IOMAP_F_INTEGRITY) {
378+
if (dio->flags & IOMAP_DIO_WRITE)
379+
fs_bio_integrity_generate(bio);
380+
else
381+
fs_bio_integrity_alloc(bio);
382+
}
383+
371384
if (dio->flags & IOMAP_DIO_WRITE)
372385
task_io_account_write(ret);
373386
else if ((dio->flags & IOMAP_DIO_USER_BACKED) &&

fs/iomap/internal.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,19 @@
44

55
#define IOEND_BATCH_SIZE 4096
66

7+
/*
8+
* Normally we can build bios as big as the data structure supports.
9+
*
10+
* But for integrity protected I/O we need to respect the maximum size of the
11+
* single contiguous allocation for the integrity buffer.
12+
*/
13+
static inline size_t iomap_max_bio_size(const struct iomap *iomap)
14+
{
15+
if (iomap->flags & IOMAP_F_INTEGRITY)
16+
return max_integrity_io_size(bdev_limits(iomap->bdev));
17+
return BIO_MAX_SIZE;
18+
}
19+
720
u32 iomap_finish_ioend_buffered_read(struct iomap_ioend *ioend);
821
u32 iomap_finish_ioend_direct(struct iomap_ioend *ioend);
922

fs/iomap/ioend.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
/*
33
* Copyright (c) 2016-2025 Christoph Hellwig.
44
*/
5+
#include <linux/bio-integrity.h>
56
#include <linux/iomap.h>
67
#include <linux/list_sort.h>
78
#include <linux/pagemap.h>
@@ -65,6 +66,8 @@ static u32 iomap_finish_ioend_buffered_write(struct iomap_ioend *ioend)
6566
folio_count++;
6667
}
6768

69+
if (bio_integrity(bio))
70+
fs_bio_integrity_free(bio);
6871
bio_put(bio); /* frees the ioend */
6972
return folio_count;
7073
}
@@ -144,6 +147,8 @@ int iomap_ioend_writeback_submit(struct iomap_writepage_ctx *wpc, int error)
144147
return error;
145148
}
146149

150+
if (wpc->iomap.flags & IOMAP_F_INTEGRITY)
151+
fs_bio_integrity_generate(&ioend->io_bio);
147152
submit_bio(&ioend->io_bio);
148153
return 0;
149154
}
@@ -165,10 +170,13 @@ static struct iomap_ioend *iomap_alloc_ioend(struct iomap_writepage_ctx *wpc,
165170
}
166171

167172
static bool iomap_can_add_to_ioend(struct iomap_writepage_ctx *wpc, loff_t pos,
168-
u16 ioend_flags)
173+
unsigned int map_len, u16 ioend_flags)
169174
{
170175
struct iomap_ioend *ioend = wpc->wb_ctx;
171176

177+
if (ioend->io_bio.bi_iter.bi_size >
178+
iomap_max_bio_size(&wpc->iomap) - map_len)
179+
return false;
172180
if (ioend_flags & IOMAP_IOEND_BOUNDARY)
173181
return false;
174182
if ((ioend_flags & IOMAP_IOEND_NOMERGE_FLAGS) !=
@@ -234,7 +242,7 @@ ssize_t iomap_add_to_ioend(struct iomap_writepage_ctx *wpc, struct folio *folio,
234242
if (pos == wpc->iomap.offset && (wpc->iomap.flags & IOMAP_F_BOUNDARY))
235243
ioend_flags |= IOMAP_IOEND_BOUNDARY;
236244

237-
if (!ioend || !iomap_can_add_to_ioend(wpc, pos, ioend_flags)) {
245+
if (!ioend || !iomap_can_add_to_ioend(wpc, pos, map_len, ioend_flags)) {
238246
new_ioend:
239247
if (ioend) {
240248
error = wpc->ops->writeback_submit(wpc, 0);
@@ -311,6 +319,14 @@ static u32 iomap_finish_ioend(struct iomap_ioend *ioend, int error)
311319

312320
if (!atomic_dec_and_test(&ioend->io_remaining))
313321
return 0;
322+
323+
if (!ioend->io_error &&
324+
bio_integrity(&ioend->io_bio) &&
325+
bio_op(&ioend->io_bio) == REQ_OP_READ) {
326+
ioend->io_error = fs_bio_integrity_verify(&ioend->io_bio,
327+
ioend->io_sector, ioend->io_size);
328+
}
329+
314330
if (ioend->io_flags & IOMAP_IOEND_DIRECT)
315331
return iomap_finish_ioend_direct(ioend);
316332
if (bio_op(&ioend->io_bio) == REQ_OP_READ)

include/linux/iomap.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ struct vm_fault;
6565
*
6666
* IOMAP_F_ATOMIC_BIO indicates that (write) I/O will be issued as an atomic
6767
* bio, i.e. set REQ_ATOMIC.
68+
*
69+
* IOMAP_F_INTEGRITY indicates that the filesystems handles integrity metadata.
6870
*/
6971
#define IOMAP_F_NEW (1U << 0)
7072
#define IOMAP_F_DIRTY (1U << 1)
@@ -79,6 +81,11 @@ struct vm_fault;
7981
#define IOMAP_F_BOUNDARY (1U << 6)
8082
#define IOMAP_F_ANON_WRITE (1U << 7)
8183
#define IOMAP_F_ATOMIC_BIO (1U << 8)
84+
#ifdef CONFIG_BLK_DEV_INTEGRITY
85+
#define IOMAP_F_INTEGRITY (1U << 9)
86+
#else
87+
#define IOMAP_F_INTEGRITY 0
88+
#endif /* CONFIG_BLK_DEV_INTEGRITY */
8289

8390
/*
8491
* Flag reserved for file system specific usage

0 commit comments

Comments
 (0)