]> www.infradead.org Git - users/hch/misc.git/commitdiff
xfs: support T10 protection information
authorChristoph Hellwig <hch@lst.de>
Fri, 31 Jan 2025 16:26:23 +0000 (17:26 +0100)
committerChristoph Hellwig <hch@lst.de>
Mon, 3 Feb 2025 09:42:17 +0000 (10:42 +0100)
Add support for generating / verifying protection information in the
file system.  This is done by hooking into the bio submission in
iomap 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.

Right now this is still pretty hacky, e.g. the single PI buffer can
get pretty gigantic and has no mempool backing it.  The deferring of
I/O completions is done unconditionally instead only when needed,
and we assume the device can actually handle these huge segments.
The latter should be fixed by doing proper splitting based on metadata
limits in the block layer, but the rest needs to be addressed here.

Signed-off-by: Christoph Hellwig <hch@lst.de>
fs/xfs/Makefile
fs/xfs/xfs_aops.c
fs/xfs/xfs_aops.h
fs/xfs/xfs_data_csum.c [new file with mode: 0644]
fs/xfs/xfs_data_csum.h [new file with mode: 0644]
fs/xfs/xfs_file.c
fs/xfs/xfs_inode.h

index 7afa51e414278e9cd39cf3888dc5713e0ca64ef1..aa8749d640e74383617828a6e50964b5a991b8fd 100644 (file)
@@ -73,6 +73,7 @@ xfs-y                         += xfs_aops.o \
                                   xfs_bmap_util.o \
                                   xfs_bio_io.o \
                                   xfs_buf.o \
+                                  xfs_data_csum.o \
                                   xfs_dahash_test.o \
                                   xfs_dir2_readdir.o \
                                   xfs_discard.o \
index 3e42a684cce1cd26eb4719598b3c7bb6f91f1139..291f5d4dbce6689f5844372c1ac5a48efadbf0cd 100644 (file)
@@ -19,6 +19,7 @@
 #include "xfs_reflink.h"
 #include "xfs_errortag.h"
 #include "xfs_error.h"
+#include "xfs_data_csum.h"
 
 struct xfs_writepage_ctx {
        struct iomap_writepage_ctx ctx;
@@ -122,6 +123,11 @@ xfs_end_ioend(
                goto done;
        }
 
+       if (bio_op(&ioend->io_bio) == REQ_OP_READ) {
+               error = xfs_data_csum_verify(ioend);
+               goto done;
+       }
+
        /*
         * Success: commit the COW or unwritten blocks if needed.
         */
@@ -175,7 +181,7 @@ xfs_end_io(
        }
 }
 
-STATIC void
+void
 xfs_end_bio(
        struct bio              *bio)
 {
@@ -417,6 +423,8 @@ xfs_submit_ioend(
 
        memalloc_nofs_restore(nofs_flag);
 
+       xfs_data_csum_generate(&ioend->io_bio);
+
        /* send ioends that might require a transaction to the completion wq */
        if (xfs_ioend_is_append(ioend) ||
            (ioend->io_flags & (IOMAP_IOEND_UNWRITTEN | IOMAP_IOEND_SHARED)))
@@ -517,19 +525,34 @@ xfs_vm_bmap(
        return iomap_bmap(mapping, block, &xfs_read_iomap_ops);
 }
 
+static void xfs_buffered_read_submit_io(struct inode *inode,
+               struct bio *bio, loff_t file_offset)
+{
+       xfs_data_csum_alloc(bio);
+       iomap_init_ioend(inode, bio, file_offset, 0);
+       bio->bi_end_io = xfs_end_bio;
+       submit_bio(bio);
+}
+
+static const struct iomap_read_folio_ops xfs_iomap_read_ops = {
+       .bio_set        = &iomap_ioend_bioset,
+       .submit_io      = xfs_buffered_read_submit_io,
+};
+
 STATIC int
 xfs_vm_read_folio(
        struct file             *unused,
        struct folio            *folio)
 {
-       return iomap_read_folio(folio, &xfs_read_iomap_ops, NULL);
+       return iomap_read_folio(folio, &xfs_read_iomap_ops,
+                       &xfs_iomap_read_ops);
 }
 
 STATIC void
 xfs_vm_readahead(
        struct readahead_control        *rac)
 {
-       iomap_readahead(rac, &xfs_read_iomap_ops, NULL);
+       iomap_readahead(rac, &xfs_read_iomap_ops, &xfs_iomap_read_ops);
 }
 
 static int
index e0bd684197643d3bcbd3460b230cd517b1ca471d..efed1ab59dbf5b0907b75899199553cbddf5d3a1 100644 (file)
@@ -10,5 +10,6 @@ extern const struct address_space_operations xfs_address_space_operations;
 extern const struct address_space_operations xfs_dax_aops;
 
 int    xfs_setfilesize(struct xfs_inode *ip, xfs_off_t offset, size_t size);
+void   xfs_end_bio(struct bio *bio);
 
 #endif /* __XFS_AOPS_H__ */
diff --git a/fs/xfs/xfs_data_csum.c b/fs/xfs/xfs_data_csum.c
new file mode 100644 (file)
index 0000000..d9d3620
--- /dev/null
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022-2025 Christoph Hellwig.
+ */
+#include "xfs.h"
+#include "xfs_format.h"
+#include "xfs_shared.h"
+#include "xfs_trans_resv.h"
+#include "xfs_mount.h"
+#include "xfs_inode.h"
+#include "xfs_cksum.h"
+#include "xfs_data_csum.h"
+#include <linux/iomap.h>
+#include <linux/blk-integrity.h>
+#include <linux/bio-integrity.h>
+
+void *
+xfs_data_csum_alloc(
+       struct bio              *bio)
+{
+       struct blk_integrity    *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
+       struct bio_integrity_payload *bip;
+       unsigned int            buf_size;
+       void                    *buf;
+
+       if (!bi)
+               return NULL;
+
+       buf_size = bio_integrity_bytes(bi, bio_sectors(bio));
+       /* XXX: this needs proper mempools */
+       /* XXX: needs (partial) zeroing if tuple_size > csum_size */
+       buf = kmalloc(buf_size, GFP_NOFS | __GFP_NOFAIL);
+       bip = bio_integrity_alloc(bio, GFP_NOFS | __GFP_NOFAIL, 1);
+       if (!bio_integrity_add_page(bio, virt_to_page(buf), buf_size,
+                       offset_in_page(buf)))
+               WARN_ON_ONCE(1);
+
+       if (bi->csum_type) {
+               if (bi->csum_type == BLK_INTEGRITY_CSUM_IP)
+                       bip->bip_flags |= BIP_IP_CHECKSUM;
+               bip->bip_flags |= BIP_CHECK_GUARD;
+       }
+       if (bi->flags & BLK_INTEGRITY_REF_TAG)
+               bip->bip_flags |= BIP_CHECK_REFTAG;
+       bip_set_seed(bip, bio->bi_iter.bi_sector);
+
+       return buf;
+}
+
+void
+xfs_data_csum_generate(
+       struct bio              *bio)
+{
+       struct blk_integrity    *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
+
+       if (!bi || !bi->csum_type)
+               return;
+
+       xfs_data_csum_alloc(bio);
+       blk_integrity_generate(bio);
+}
+
+int
+xfs_data_csum_verify(
+       struct iomap_ioend      *ioend)
+{
+       struct bio              *bio = &ioend->io_bio;
+       struct blk_integrity    *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
+
+       if (!bi || !bi->csum_type)
+               return 0;
+       return blk_integrity_verify_all(bio, ioend->io_sector);
+}
diff --git a/fs/xfs/xfs_data_csum.h b/fs/xfs/xfs_data_csum.h
new file mode 100644 (file)
index 0000000..f32215e
--- /dev/null
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+struct iomap_ioend;
+
+void *xfs_data_csum_alloc(struct bio *bio);
+void xfs_data_csum_generate(struct bio *bio);
+int xfs_data_csum_verify(struct iomap_ioend *ioend);
index f7a7d89c345ec403a2684177b020fc067059b020..0d64c54017f096cdcfb84e49fef9b71801fb36a1 100644 (file)
@@ -25,6 +25,8 @@
 #include "xfs_iomap.h"
 #include "xfs_reflink.h"
 #include "xfs_file.h"
+#include "xfs_data_csum.h"
+#include "xfs_aops.h"
 
 #include <linux/dax.h>
 #include <linux/falloc.h>
@@ -227,6 +229,20 @@ xfs_ilock_iocb_for_write(
        return 0;
 }
 
+static void xfs_dio_read_submit_io(const struct iomap_iter *iter,
+               struct bio *bio, loff_t file_offset)
+{
+       xfs_data_csum_alloc(bio);
+       iomap_init_ioend(iter->inode, bio, file_offset, IOMAP_IOEND_DIRECT);
+       bio->bi_end_io = xfs_end_bio;
+       submit_bio(bio);
+}
+
+static const struct iomap_dio_ops xfs_dio_read_ops = {
+       .bio_set        = &iomap_ioend_bioset,
+       .submit_io      = xfs_dio_read_submit_io,
+};
+
 STATIC ssize_t
 xfs_file_dio_read(
        struct kiocb            *iocb,
@@ -245,7 +261,8 @@ xfs_file_dio_read(
        ret = xfs_ilock_iocb(iocb, XFS_IOLOCK_SHARED);
        if (ret)
                return ret;
-       ret = iomap_dio_rw(iocb, to, &xfs_read_iomap_ops, NULL, 0, NULL, 0);
+       ret = iomap_dio_rw(iocb, to, &xfs_read_iomap_ops, &xfs_dio_read_ops, 0,
+                       NULL, 0);
        xfs_iunlock(ip, XFS_IOLOCK_SHARED);
 
        return ret;
@@ -578,8 +595,16 @@ out:
        return error;
 }
 
+static void xfs_dio_write_submit_io(const struct iomap_iter *iter,
+               struct bio *bio, loff_t file_offset)
+{
+       xfs_data_csum_generate(bio);
+       submit_bio(bio);
+}
+
 static const struct iomap_dio_ops xfs_dio_write_ops = {
        .end_io         = xfs_dio_write_end_io,
+       .submit_io      = xfs_dio_write_submit_io,
 };
 
 /*
index c08093a65352ecc99ead78ba6d9354334d67b3a0..ff346bbe454c02d78bc86f253232267738d6336b 100644 (file)
@@ -609,10 +609,8 @@ int        xfs_break_layouts(struct inode *inode, uint *iolock,
 
 static inline void xfs_update_stable_writes(struct xfs_inode *ip)
 {
-       if (bdev_stable_writes(xfs_inode_buftarg(ip)->bt_bdev))
-               mapping_set_stable_writes(VFS_I(ip)->i_mapping);
-       else
-               mapping_clear_stable_writes(VFS_I(ip)->i_mapping);
+       /* XXX: unconditional for now */
+       mapping_set_stable_writes(VFS_I(ip)->i_mapping);
 }
 
 /*