* 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"
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;
}
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)
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;
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;
}
* 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>
{
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);
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);
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) &&
#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);
/*
* Copyright (c) 2016-2025 Christoph Hellwig.
*/
+#include <linux/bio-integrity.h>
#include <linux/iomap.h>
#include <linux/list_sort.h>
#include <linux/pagemap.h>
folio_count++;
}
+ if (bio_integrity(bio))
+ fs_bio_integrity_free(bio);
bio_put(bio); /* frees the ioend */
return folio_count;
}
return error;
}
+ if (wpc->iomap.flags & IOMAP_F_INTEGRITY)
+ fs_bio_integrity_generate(&ioend->io_bio);
submit_bio(&ioend->io_bio);
return 0;
}
}
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) !=
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);
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)
*
* 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)
#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