]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
iomap: teach iomap to read files with fsverity
authorAndrey Albershteyn <aalbersh@kernel.org>
Wed, 20 May 2026 12:37:06 +0000 (14:37 +0200)
committerChristian Brauner <brauner@kernel.org>
Fri, 5 Jun 2026 11:36:22 +0000 (13:36 +0200)
Obtain fsverity info for folios with file data and fsverity metadata.
Filesystem can pass vi down to ioend and then to fsverity for
verification. This is different from other filesystems ext4, f2fs, btrfs
supporting fsverity, these filesystems don't need fsverity_info for
reading fsverity metadata. While reading merkle tree iomap requires
fsverity info to synthesize hashes for zeroed data block.

fsverity metadata has two kinds of holes - ones in merkle tree and one
after fsverity descriptor.

Merkle tree holes are blocks full of hashes of zeroed data blocks. These
are not stored on the disk but synthesized on the fly. This saves a bit
of space for sparse files. Due to this iomap also need to lookup
fsverity_info for folios with fsverity metadata. ->vi has a hash of the
zeroed data block which will be used to fill the merkle tree block.

The hole past descriptor is interpreted as end of metadata region. As we
don't have EOF here we use this hole as an indication that rest of the
folio is empty. This patch marks rest of the folio beyond fsverity
descriptor as uptodate.

For file data, fsverity needs to verify consistency of the whole file
against the root hash, hashes of holes are included in the merkle tree.
Verify them too.

Issue reading of fsverity merkle tree on the fsverity inodes. This way
metadata will be available at I/O completion time.

Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
Link: https://patch.msgid.link/20260520123722.405752-9-aalbersh@kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
fs/iomap/buffered-io.c
fs/iomap/ioend.c
include/linux/iomap.h

index d9462f28afbd33d93131edb1deef0a92a7e40476..f9cc5a32e222da4bf0a50c5c466663f68f2f3cc5 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/swap.h>
 #include <linux/migrate.h>
 #include <linux/fserror.h>
+#include <linux/fsverity.h>
 #include "internal.h"
 #include "trace.h"
 
@@ -561,9 +562,27 @@ static int iomap_read_folio_iter(struct iomap_iter *iter,
                if (plen == 0)
                        return 0;
 
-               /* zero post-eof blocks as the page may be mapped */
-               if (iomap_block_needs_zeroing(iter, pos)) {
+               /*
+                * Handling of fsverity "holes". We hit this for two case:
+                *   1. No need to go further, the hole after fsverity
+                *      descriptor is the end of the fsverity metadata.
+                *
+                *   2. This folio contains merkle tree blocks which need to be
+                *      synthesized. If we already have fsverity info (ctx->vi)
+                *      synthesize these blocks.
+                */
+               if ((iomap->flags & IOMAP_F_FSVERITY) &&
+                   iomap->type == IOMAP_HOLE) {
+                       if (ctx->vi)
+                               fsverity_fill_zerohash(folio, poff, plen,
+                                                      ctx->vi);
+                       iomap_set_range_uptodate(folio, poff, plen);
+               } else if (iomap_block_needs_zeroing(iter, pos)) {
+                       /* zero post-eof blocks as the page may be mapped */
                        folio_zero_range(folio, poff, plen);
+                       if (ctx->vi &&
+                           !fsverity_verify_blocks(ctx->vi, folio, plen, poff))
+                               return -EIO;
                        iomap_set_range_uptodate(folio, poff, plen);
                } else {
                        if (!*bytes_submitted)
@@ -614,6 +633,15 @@ void iomap_read_folio(const struct iomap_ops *ops,
 
        trace_iomap_readpage(iter.inode, 1);
 
+       /*
+        * Fetch fsverity_info for both data and fsverity metadata, as iomap
+        * needs zeroed hash for merkle tree block synthesis
+        */
+       ctx->vi = fsverity_get_info(iter.inode);
+       if (ctx->vi && iter.pos < i_size_read(iter.inode))
+               fsverity_readahead(ctx->vi, folio->index,
+                                  folio_nr_pages(folio));
+
        while ((ret = iomap_iter(&iter, ops)) > 0)
                iter.status = iomap_read_folio_iter(&iter, ctx,
                                &bytes_submitted);
@@ -681,6 +709,15 @@ void iomap_readahead(const struct iomap_ops *ops,
 
        trace_iomap_readahead(rac->mapping->host, readahead_count(rac));
 
+       /*
+        * Fetch fsverity_info for both data and fsverity metadata, as iomap
+        * needs zeroed hash for merkle tree block synthesis
+        */
+       ctx->vi = fsverity_get_info(iter.inode);
+       if (ctx->vi && iter.pos < i_size_read(iter.inode))
+               fsverity_readahead(ctx->vi, readahead_index(rac),
+                               readahead_count(rac));
+
        while (iomap_iter(&iter, ops) > 0)
                iter.status = iomap_readahead_iter(&iter, ctx,
                                        &cur_bytes_submitted);
index acf3cf98b23a9bc17af9d6791a2aaa04fd5d6ff1..f7c3e0c70fd72b8110010888bf8bc55938d9ec42 100644 (file)
@@ -28,6 +28,7 @@ struct iomap_ioend *iomap_init_ioend(struct inode *inode,
        ioend->io_offset = file_offset;
        ioend->io_size = bio->bi_iter.bi_size;
        ioend->io_sector = bio->bi_iter.bi_sector;
+       ioend->io_vi = NULL;
        ioend->io_private = NULL;
        return ioend;
 }
index 5b2b40e81b6116b1c0cde4ff27ede76d0d6caa46..1be2e16b696a8f6157b93479795fe689f33b874f 100644 (file)
@@ -429,6 +429,7 @@ struct iomap_ioend {
        loff_t                  io_offset;      /* offset in the file */
        sector_t                io_sector;      /* start sector of ioend */
        void                    *io_private;    /* file system private data */
+       struct fsverity_info    *io_vi;         /* fsverity info */
        struct bio              io_bio;         /* MUST BE LAST! */
 };
 
@@ -503,6 +504,7 @@ struct iomap_read_folio_ctx {
        struct readahead_control *rac;
        void                    *read_ctx;
        loff_t                  read_ctx_file_offset;
+       struct fsverity_info    *vi;
 };
 
 struct iomap_read_ops {