fs-verity support for XFS with post EOF merkle tree
Subsystems (8)
v10 cover fs-verity support for XFS with post EOF merkle tree
Hi all,
This patch series adds fs-verity support for XFS. This version stores merkle tree beyond end of the file, the same way as ext4 does it. The difference is that verity descriptor is stored at the next aligned 64k block after the merkle tree last block. This is done due to sparse merkle tree which doesn't store hashes of zero data blocks.
The patchset starts with a few fs-verity preparation patches. Then, a few patches to allow iomap to work in post EOF region. The XFS fs-verity implementation follows.
The tree is read by iomap into page cache at offset of next largest folio past end of file. The same offset is used for on-disk.
This patchsets also synthesizes merkle tree block full of hashes of zeroed data blocks. This merkle blocks are not stored on disk, they are holes in the tree.
Testing. The -g verity is passing for 1k, 8k and 4k with/without quota on 4k and 64k page size systems. Tested -g quick for enabled/disabled fsverity. Also, overlay/080 overlay/089 with XFS as base. Compile test for FSVERITY=no/yes.
This series based on v7.1-rc4.
kernel:
https://git.kernel.org/pub/scm/linux/kernel/git/aalbersh/xfs-linux.git/log/?h=b4/fsverity
xfsprogs:
https://github.com/alberand/xfsprogs/tree/b4/fsverity
xfstests:
https://github.com/alberand/xfstests/tree/b4/fsverity
1: https://lore.kernel.org/linux-xfs/[email protected]/
---
Changes in v10:
- Rebase to v7.1-rc3 with relevant adjustments
- Initialize ioend->io_vi to NULL to not get write work onto verity wq
- Range diff below
Changes in v9:
- Fix fsverity_fill_zerohash() parameter names
- A few fixes found by sashiko.dev:
- Replace ip->i_mount->m_attr_geo->blksize with m_sb.sb_blocksize
- Don't call xfs_trans_cancel() after xfs_trans_commit() in xfs_fsverity_end_enable()
- Call xfs_fsverity_delete_metadata() if verity enable failed
- Change start/end type from xfs_fileoff_t to loff_t
- Return xfs_trans_commit() error from
xfs_fsverity_cancel_unwritten()
Changes in v8:
- Return fsverity_ensure_verity_info() errors from
ovl_ensure_verity_loaded()
Changes in v7:
- Move kerneldoc to fsverity_ensure_verity_info() definition
- Drop patch adding XFS traces
- Fix overly long line in the comment
- Make order of fserror and fsverity_error consistent
- Add overlay patch converting to fsverity_ensure_verity_info()
Changes in v6:
- Removed stub for fsverity_ensure_verity_info() as it's optimized out
- Rename fsverity_folio_zero_hash() to fsverify_fill_zerohash()
- Merge patches 8 to 10 into one
- Merge patch gerating zero_hash and fsverity_fill_zerohash() into one
- Add kerneldoc to fsverity_ensure_verity_info()
- Add comments to iomap_block_needs_zeroing()
Changes in v5:
- Add fserror_report_data_lost() for data blocks in page spanning EOF
- Issue fsverity metadata readahead in data readahead
- iomap_fsverity_write() return type fix
- Use of S_ISREG(mode)
- Make 65536 #define instead of open-coded
- Use transaction per unwritten extent removal
- Fetch fsverity_info for all fsverity metadata
- Revert fsverity_folio_zero_hash() stub as used in iomap
- Extend cancel_unwritten to whole file range to remove cow leftovers
- Drop delayed allocation on the COW fork on fsverity completion
Changes in v4:
- Use fserror interface in fsverity instead of fs callback
- Hoist pagecache_read from f2fs/ext4 to fsverity
- Refactor iomap code
- Fetch fsverity_info only for file data and merkle tree holes
- Do not disable preallocation, remove unwritten extents instead
- Offload fsverity hash I/O to fsverity workqueue in read path
- Store merkle tree at round_up(i_size, 64k)
- Add a spacing between merkle tree and fsverity descriptor as next 64k
aligned block
- Squash helpers into first user commits
- Squash on-disk format changes into single commit
- Drop different offset for pagecache/on-disk
- Don't zero out pages in higher order folios in write path
- Link to v3: https://lore.kernel.org/fsverity/[email protected]/T/#t
Changes in v3:
- Different on-disk and pagecache offset
- Use read path ioends
- Switch to hashtable fsverity info
- Synthesize merkle tree blocks full of zeroes
- Other minor refactors
- Link to v2: https://lore.kernel.org/fsverity/20260114164210.GO15583@frogsfrogsfrogs/T/#t
Changes in v2:
- Move to VFS interface for merkle tree block reading
- Drop patchset for per filesystem workqueues
- Change how offsets of the descriptor and tree metadata is calculated
- Store fs-verity descriptor in data fork side by side with merkle tree
- Simplify iomap changes, remove interface for post eof read/write
- Get rid of extended attribute implementation
- Link to v1: https://lore.kernel.org/r/[email protected]
-- >8 --
1: aabd8b112385 < -: ------------ fs-verity support for XFS with post EOF merkle tree -: ------------ > 1: ec15fda2f683 fs-verity support for XFS with post EOF merkle tree 2: f3a3cc5b6ab2 = 2: 97d22944e17f fsverity: report validation errors through fserror to fsnotify 3: c8155669bdff = 3: f717e55c313c fsverity: expose ensure_fsverity_info() 4: 83262640936a ! 4: 38381b5ec63e ovl: use core fsverity ensure info interface
@@ fs/overlayfs/util.c: char *ovl_get_redirect_xattr(struct ovl_fs *ofs, const stru
struct inode *inode = d_inode(datapath->dentry);
- struct file *filp;
-- if (IS_VERITY(inode) && fsverity_get_info(inode) == NULL) { +- if (!fsverity_active(inode) && IS_VERITY(inode)) {
- /*
- * If this inode was not yet opened, the verity info hasn't been
- * loaded yet, so we need to do that here to force it into memory.
5: 6d63f3ee7604 = 5: b4b86f757eaa fsverity: generate and store zero-block hash 6: 800753879b5c = 6: f9d2eaf0fdcd fsverity: pass digest size and hash of the all-zeroes block to ->write 7: c4e06f9d9c08 = 7: 87d8f4495aa5 fsverity: hoist pagecache_read from f2fs/ext4 to fsverity 8: 34be1a25ffd2 = 8: 2da572c7a3bf iomap: introduce IOMAP_F_FSVERITY and teach writeback to handle fsverity 9: 728df1f13e31 ! 9: 3669ecfb610e iomap: teach iomap to read files with fsverity
@@ fs/iomap/buffered-io.c: void iomap_readahead(const struct iomap_ops *ops,
iter.status = iomap_readahead_iter(&iter, ctx,
&cur_bytes_submitted);
- ## fs/iomap/ioend.c ##
-@@ fs/iomap/ioend.c: 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;
- }
-
## include/linux/iomap.h ##
@@ include/linux/iomap.h: struct iomap_ioend {
loff_t io_offset; /* offset in the file */
10: 9eb9dd92b762 = 10: a8989fbd29f1 iomap: introduce iomap_fsverity_write() for writing fsverity metadata 11: 27602df28674 = 11: 04b23426b5cf xfs: introduce fsverity on-disk changes 12: 544c81d26e7c = 12: ba69a8817d13 xfs: initialize fs-verity on file open 13: 6158f03b2ad4 = 13: e2b59e6cd4da xfs: don't allow to enable DAX on fs-verity sealed inode 14: 03b1f44c53b2 = 14: 9e2628f17346 xfs: disable direct read path for fs-verity files 15: 96c9f90ade98 = 15: 3dea5f7e5481 xfs: handle fsverity I/O in write/read path 16: e864ce49e5b3 = 16: ff837a33e8f5 xfs: use read ioend for fsverity data verification 17: b06bb3eefa38 = 17: 5c79a1e5f6ff xfs: add fs-verity support 18: 567d5190bfd9 = 18: af3c36498d1c xfs: remove unwritten extents after preallocations in fsverity metadata 19: b952307f139d = 19: 744cf7ec0842 xfs: add fs-verity ioctls 20: 3f5382888801 = 20: d47aac1643a7 xfs: advertise fs-verity being available on filesystem 21: b87668403694 = 21: 48e83ac7e6c2 xfs: check and repair the verity inode flag state 22: eec854161680 = 22: 2a9f58d29909 xfs: introduce health state for corrupted fsverity metadata 23: 9ddc2cf10f52 = 23: b5bf49f2e750 xfs: enable ro-compat fs-verity flag
Andrey Albershteyn (20):
fsverity: report validation errors through fserror to fsnotify
fsverity: expose ensure_fsverity_info()
ovl: use core fsverity ensure info interface
fsverity: generate and store zero-block hash
fsverity: pass digest size and hash of the all-zeroes block to ->write
fsverity: hoist pagecache_read from f2fs/ext4 to fsverity
iomap: introduce IOMAP_F_FSVERITY and teach writeback to handle
fsverity
iomap: teach iomap to read files with fsverity
iomap: introduce iomap_fsverity_write() for writing fsverity metadata
xfs: introduce fsverity on-disk changes
xfs: initialize fs-verity on file open
xfs: don't allow to enable DAX on fs-verity sealed inode
xfs: disable direct read path for fs-verity files
xfs: handle fsverity I/O in write/read path
xfs: use read ioend for fsverity data verification
xfs: add fs-verity support
xfs: remove unwritten extents after preallocations in fsverity
metadata
xfs: add fs-verity ioctls
xfs: introduce health state for corrupted fsverity metadata
xfs: enable ro-compat fs-verity flag
Darrick J. Wong (2):
xfs: advertise fs-verity being available on filesystem
xfs: check and repair the verity inode flag state
fs/btrfs/verity.c | 6 +- fs/ext4/verity.c | 36 +-- fs/f2fs/verity.c | 34 +-- fs/iomap/buffered-io.c | 109 +++++++- fs/iomap/ioend.c | 1 + fs/iomap/trace.h | 3 +- fs/overlayfs/util.c | 14 +- fs/verity/enable.c | 4 +- fs/verity/fsverity_private.h | 3 + fs/verity/measure.c | 4 +- fs/verity/open.c | 25 +- fs/verity/pagecache.c | 55 ++++ fs/verity/verify.c | 4 + fs/xfs/Makefile | 1 + fs/xfs/libxfs/xfs_bmap.c | 7 + fs/xfs/libxfs/xfs_format.h | 35 ++- fs/xfs/libxfs/xfs_fs.h | 2 + fs/xfs/libxfs/xfs_health.h | 4 +- fs/xfs/libxfs/xfs_inode_buf.c | 8 + fs/xfs/libxfs/xfs_inode_util.c | 2 + fs/xfs/libxfs/xfs_sb.c | 4 + fs/xfs/scrub/attr.c | 7 + fs/xfs/scrub/common.c | 53 ++++ fs/xfs/scrub/common.h | 2 + fs/xfs/scrub/inode.c | 7 + fs/xfs/scrub/inode_repair.c | 36 +++ fs/xfs/xfs_aops.c | 62 ++++- fs/xfs/xfs_bmap_util.c | 8 + fs/xfs/xfs_file.c | 19 +- fs/xfs/xfs_fsverity.c | 457 +++++++++++++++++++++++++++++++++ fs/xfs/xfs_fsverity.h | 28 ++ fs/xfs/xfs_health.c | 1 + fs/xfs/xfs_inode.h | 6 + fs/xfs/xfs_ioctl.c | 14 + fs/xfs/xfs_iomap.c | 15 +- fs/xfs/xfs_iops.c | 4 + fs/xfs/xfs_message.c | 4 + fs/xfs/xfs_message.h | 1 + fs/xfs/xfs_mount.h | 4 + fs/xfs/xfs_super.c | 7 + include/linux/fsverity.h | 18 +- include/linux/iomap.h | 13 + 42 files changed, 1020 insertions(+), 107 deletions(-) create mode 100644 fs/xfs/xfs_fsverity.c create mode 100644 fs/xfs/xfs_fsverity.h
Signature · 1 line
2.51.2
PATCH v10 1/22 fsverity: report validation errors through fserror to fsnotify
Reported verification errors to fsnotify through recently added fserror interface.
--- fs/verity/verify.c | 4 ++++ 1 file changed, 4 insertions(+)
fs/verity/verify.c +4 -0
@@ -9,6 +9,7 @@#include <linux/bio.h> #include <linux/export.h> +#include <linux/fserror.h> #define FS_VERITY_MAX_PENDING_BLOCKS 2
@@ -205,6 +206,8 @@ static bool verify_data_block(struct fsverity_info *vi,if (memchr_inv (dblock->data,0 , params->block_size)) {fsverity_err (inode,"FILE CORRUPTED! Data past EOF is not zeroed" ); +fserror_report_data_lost (inode, data_pos, + params->block_size,GFP_NOFS );return false; }return true;
@@ -312,6 +315,7 @@ static bool verify_data_block(struct fsverity_info *vi, data_pos, level -1 , params->hash_alg->name, hsize, want_hash, params->hash_alg->name, hsize, level == 0 ? dblock->real_hash : real_hash); +fserror_report_data_lost (inode, data_pos, params->block_size,GFP_NOFS ); error:for (; level >0 ; level--) {kunmap_local (hblocks[level -1 ].addr);
Signature · 1 line
2.51.2
PATCH v10 2/22 fsverity: expose ensure_fsverity_info()
In reply to Andrey AlbershteynThis function will be used by XFS's scrub to force fsverity activation, therefore, to read fsverity context.
--- fs/verity/open.c | 22 ++++++++++++++++++++-- include/linux/fsverity.h | 2 ++ 2 files changed, 22 insertions(+), 2 deletions(-)
fs/verity/open.c +20 -2
@@ -344,7 +344,24 @@ int fsverity_get_descriptor(struct inode *inode,return 0 ; } -static int ensure_verity_info (struct inode *inode) +/** +* fsverity_ensure_verity_info() - cache verity info if it's not already cached +* @inode: the inode for which verity info should be cached +* +* Ensure this inode has verity info attached to it, it's assumed the inode +* already has fsverity enabled. Read fsverity descriptor and creates verity +* based on that. +* +* This needs to be called at least once before any of the inode's data +* can be verified (and thus read at all) or the inode's fsverity digest +* retrieved. fsverity_file_open() calls this already, which handles +* normal file accesses. If a filesystem does any internal (i.e. not +* associated with a file descriptor) reads of the file's data or +* fsverity digest, it must call this explicitly before doing so. +* +* Return: 0 on success, -errno on failure +*/ +int fsverity_ensure_verity_info (struct inode *inode) {struct fsverity_info *vi =fsverity_get_info (inode), *found;struct fsverity_descriptor *desc;
@@ -380,12 +397,13 @@ static int ensure_verity_info(struct inode *inode)kfree (desc);return err; } +EXPORT_SYMBOL_GPL (fsverity_ensure_verity_info);int __fsverity_file_open (struct inode *inode,struct file *filp) {if (filp->f_mode &FMODE_WRITE )return -EPERM ; -return ensure_verity_info (inode); +return fsverity_ensure_verity_info (inode); }EXPORT_SYMBOL_GPL (__fsverity_file_open);
include/linux/fsverity.h +2 -0
@@ -309,6 +309,8 @@ static inline int fsverity_file_open(struct inode *inode, struct file *filp)return 0 ; } +int fsverity_ensure_verity_info (struct inode *inode); +void fsverity_cleanup_inode (struct inode *inode);struct page *generic_read_merkle_tree_page (struct inode *inode,pgoff_t index);
Signature · 1 line
2.51.2
PATCH v10 3/22 ovl: use core fsverity ensure info interface
In reply to Andrey Albershteynfsverity now exposes fsverity_ensure_verity_info() which could be used instead of opening file to ensure that fsverity info is loaded and attached to inode.
--- fs/overlayfs/util.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-)
fs/overlayfs/util.c +3 -11
@@ -16,6 +16,7 @@#include <linux/namei.h> #include <linux/ratelimit.h> #include <linux/overflow.h> +#include <linux/fsverity.h> #include "overlayfs.h" /* Get write access to upper mnt - may fail if upper sb was remounted ro */
@@ -1352,18 +1353,9 @@ char *ovl_get_redirect_xattr(struct ovl_fs *ofs, const struct path *path, int paint ovl_ensure_verity_loaded (const struct path *datapath) {struct inode *inode =d_inode (datapath->dentry); -struct file *filp; -if (IS_VERITY (inode) &&fsverity_get_info (inode) ==NULL ) { -/* -* If this inode was not yet opened, the verity info hasn't been -* loaded yet, so we need to do that here to force it into memory. -*/ - filp =kernel_file_open (datapath,O_RDONLY ,current_cred ()); -if (IS_ERR (filp)) -return PTR_ERR (filp); -fput (filp); - } +if (fsverity_active (inode)) +return fsverity_ensure_verity_info (inode);return 0 ; }
Signature · 1 line
2.51.2
Re: [PATCH v10 03/22] ovl: use core fsverity ensure info interface
Quoted 6 lines · Andrey Albershteyn
fsverity now exposes
fsverity_ensure_verity_info()which could be used instead of opening file to ensure that fsverity info is loaded and attached to inode.Signed-off-by Andrey Albershteyn <[email protected]>Acked-by Amir Goldstein <[email protected]>
Amir, Eric, this is the last patch missing a review. Could one of you have a look at it. Not sure who should review this.
Signature · 1 line
- Andrey
Re: [PATCH v10 03/22] ovl: use core fsverity ensure info interface
Quoted 1 line
the last patch missing a review
oh sorry, the 04 patch is also one without
Signature · 1 line
- Andrey
Re: [PATCH v10 03/22] ovl: use core fsverity ensure info interface
In reply to Andrey AlbershteynQuoted 11 lines · Andrey Albershteyn
Quoted 6 lines · Andrey Albershteyn
fsverity now exposes
fsverity_ensure_verity_info()which could be used instead of opening file to ensure that fsverity info is loaded and attached to inode.Signed-off-by Andrey Albershteyn <[email protected]>Acked-by Amir Goldstein <[email protected]>Amir, Eric, this is the last patch missing a review. Could one of you have a look at it. Not sure who should review this.
Feel free to upgrade my ack to:
Thanks,
Amir.
Re: [PATCH v10 03/22] ovl: use core fsverity ensure info interface
In reply to Andrey AlbershteynQuoted 9 lines · Andrey Albershteyn
fsverity now exposes
fsverity_ensure_verity_info()which could be used instead of opening file to ensure that fsverity info is loaded and attached to inode.Signed-off-by Andrey Albershteyn <[email protected]>Acked-by Amir Goldstein <[email protected]>--- fs/overlayfs/util.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-)
I'm still confused by the new implementation of fsverity_active() that got introduced by "fsverity: use a hashtable to find the fsverity_info", though. I should have caught this during review of that commit. For one its comment is outdated, but also the memory barrier seems to be specific to the fsverity_get_info() caller and probably should be moved to there. Anyway, that's not directly related to this patch.
- Eric
Amir Goldstein
maintainerRe: [PATCH v10 03/22] ovl: use core fsverity ensure info interface
Quoted 12 lines · Eric Biggers
Quoted 9 lines · Andrey Albershteyn
fsverity now exposes
fsverity_ensure_verity_info()which could be used instead of opening file to ensure that fsverity info is loaded and attached to inode.Signed-off-by Andrey Albershteyn <[email protected]>Acked-by Amir Goldstein <[email protected]>--- fs/overlayfs/util.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-)
Quoted 8 lines
Reviewed-by Eric Biggers <[email protected]>I'm still confused by the new implementation of
fsverity_active()that got introduced by "fsverity: use a hashtable to find thefsverity_info", though. I should have caught this during review of that commit. For one its comment is outdated, but also the memory barrier seems to be specific to thefsverity_get_info()caller and probably should be moved to there. Anyway, that's not directly related to this patch.
Eric, Andrey,
Did you see the Sashiko review for this patch and others in this series?
https://sashiko.dev/#/patchset/20260520123722.405752-1-aalbersh%40kernel.org
It annotated some review comments as high and critical. For this patch it is about interaction with fscrypt.
Please take a look and say if this is concerning or false positive.
Thanks,
Amir.
Eric Biggers
maintainerRe: [PATCH v10 03/22] ovl: use core fsverity ensure info interface
Quoted 24 lines · Amir Goldstein
Quoted 12 lines · Eric Biggers
Quoted 9 lines · Andrey Albershteyn
fsverity now exposes
fsverity_ensure_verity_info()which could be used instead of opening file to ensure that fsverity info is loaded and attached to inode.Signed-off-by Andrey Albershteyn <[email protected]>Acked-by Amir Goldstein <[email protected]>--- fs/overlayfs/util.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-)Quoted 8 lines
Reviewed-by Eric Biggers <[email protected]>I'm still confused by the new implementation of
fsverity_active()that got introduced by "fsverity: use a hashtable to find thefsverity_info", though. I should have caught this during review of that commit. For one its comment is outdated, but also the memory barrier seems to be specific to thefsverity_get_info()caller and probably should be moved to there. Anyway, that's not directly related to this patch.Eric, Andrey,
Quoted 8 lines
Did you see the Sashiko review for this patch and others in this series?
https://sashiko.dev/#/patchset/20260520123722.405752-1-aalbersh%40kernel.org
It annotated some review comments as high and critical. For this patch it is about interaction with fscrypt.
Please take a look and say if this is concerning or false positive.
Yes, this patch is broken and should be dropped. I need to remember to look at the Sashiko reviews for other people's patches and not just trust that the submitter will. Fortunately this one wasn't applied yet.
I pointed out the HIGHMEM performance bug in
"fsverity: generate and store zero-block hash" earlier
(https://lore.kernel.org/linux-fsdevel/20260401222717.GH2466@quark/). I assume it was decided that no one will care about the combination of XFS && fsverity && HIGHMEM. But the XFS folks should double-check that.
Andrey, could you check the Sashiko reviews for the other patches too?
- Eric
Re: [PATCH v10 03/22] ovl: use core fsverity ensure info interface
Quoted 38 lines · Eric Biggers
Quoted 24 lines · Amir Goldstein
Quoted 12 lines · Eric Biggers
Quoted 9 lines · Andrey Albershteyn
fsverity now exposes
fsverity_ensure_verity_info()which could be used instead of opening file to ensure that fsverity info is loaded and attached to inode.Signed-off-by Andrey Albershteyn <[email protected]>Acked-by Amir Goldstein <[email protected]>--- fs/overlayfs/util.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-)Quoted 8 lines
Reviewed-by Eric Biggers <[email protected]>I'm still confused by the new implementation of
fsverity_active()that got introduced by "fsverity: use a hashtable to find thefsverity_info", though. I should have caught this during review of that commit. For one its comment is outdated, but also the memory barrier seems to be specific to thefsverity_get_info()caller and probably should be moved to there. Anyway, that's not directly related to this patch.Eric, Andrey,
Quoted 8 lines
Did you see the Sashiko review for this patch and others in this series?
https://sashiko.dev/#/patchset/20260520123722.405752-1-aalbersh%40kernel.org
It annotated some review comments as high and critical. For this patch it is about interaction with fscrypt.
Please take a look and say if this is concerning or false positive.
Yes, this patch is broken and should be dropped. I need to remember to look at the Sashiko reviews for other people's patches and not just trust that the submitter will. Fortunately this one wasn't applied yet.
Quoted 7 lines
I pointed out the HIGHMEM performance bug in
"fsverity: generate and store zero-block hash" earlier
(https://lore.kernel.org/linux-fsdevel/20260401222717.GH2466@quark/). I assume it was decided that no one will care about the combination of XFS && fsverity && HIGHMEM. But the XFS folks should double-check that.Andrey, could you check the Sashiko reviews for the other patches too?
Sure, I will go through them
Signature · 1 line
- Andrey
PATCH v10 4/22 fsverity: generate and store zero-block hash
In reply to Andrey AlbershteynCompute the hash of one filesystem block's worth of zeros. A filesystem implementation can decide to elide merkle tree blocks containing only this hash and synthesize the contents at read time.
Let's pretend that there's a file containing 131 data block and whose merkle tree looks roughly like this:
root
+--leaf0
| +--data0
| +--data1
| +--...
| `--data128
`--leaf1
+--data129
+--data130
`--data131If data[0-128] are sparse holes, then leaf0 will contain a repeating sequence of @zero_digest. Therefore, leaf0 need not be written to disk because its contents can be synthesized.
A subsequent xfs patch will use this to reduce the size of the merkle tree when dealing with sparse gold master disk images and the like.
Note that this works only on the first-level (data holes). fsverity doesn't store/generate zero_digest for any higher levels.
Add a helper to pre-fill folio with hashes of empty blocks. This will be used by iomap to synthesize blocks full of zero hashes on the fly.
--- fs/verity/fsverity_private.h | 3 +++ fs/verity/measure.c | 4 ++-- fs/verity/open.c | 3 +++ fs/verity/pagecache.c | 22 ++++++++++++++++++++++ include/linux/fsverity.h | 8 ++++++++ 5 files changed, 38 insertions(+), 2 deletions(-)
fs/verity/fsverity_private.h +3 -0
@@ -53,6 +53,9 @@ struct merkle_tree_params {u64 tree_size;/* Merkle tree size in bytes */ unsigned long tree_pages;/* Merkle tree size in pages */ +/* the hash of an all-zeroes block */ +u8 zero_digest[FS_VERITY_MAX_DIGEST_SIZE ]; +/* * Starting block index for each tree level, ordered from leaf level (0) * to root level ('num_levels - 1')
fs/verity/measure.c +2 -2
@@ -68,8 +68,8 @@ EXPORT_SYMBOL_GPL(fsverity_ioctl_measure);* @alg: (out) the digest's algorithm, as a FS_VERITY_HASH_ALG_* value * @halg: (out) the digest's algorithm, as a HASH_ALGO_* value * -* Retrieves the fsverity digest of the given file. The file must have been -* opened at least once since the inode was last loaded into the inode cache; +* Retrieves the fsverity digest of the given file. The +* fsverity_ensure_verity_info() must be called on the inode beforehand; * otherwise this function will not recognize when fsverity is enabled. * * The file's fsverity digest consists of @raw_digest in combination with either
fs/verity/open.c +3 -0
@@ -153,6 +153,9 @@ int fsverity_init_merkle_tree_params(struct merkle_tree_params *params, goto out_err; } +fsverity_hash_block (params,page_address (ZERO_PAGE (0 )), + params->zero_digest); + params->tree_size = offset << log_blocksize; params->tree_pages =PAGE_ALIGN (params->tree_size) >>PAGE_SHIFT ;return 0 ;
fs/verity/pagecache.c +22 -0
@@ -2,6 +2,7 @@/* * Copyright 2019 Google LLC */ +#include "fsverity_private.h" #include <linux/export.h> #include <linux/fsverity.h>
@@ -56,3 +57,24 @@ void generic_readahead_merkle_tree(struct inode *inode, pgoff_t index,folio_put (folio); }EXPORT_SYMBOL_GPL (generic_readahead_merkle_tree); + +/** +* fsverity_fill_zerohash() - fill folio with hashes of zero data block +* @folio: folio to fill +* @offset: offset in the folio to start +* @len: length of the range to fill with hashes +* @vi: fsverity info +*/ +void fsverity_fill_zerohash (struct folio *folio,size_t offset,size_t len, +struct fsverity_info *vi) +{ +size_t off = offset; + +WARN_ON_ONCE (!IS_ALIGNED (offset, vi->tree_params.digest_size)); +WARN_ON_ONCE (!IS_ALIGNED (len, vi->tree_params.digest_size)); + +for (; off < (offset + len); off += vi->tree_params.digest_size) +memcpy_to_folio (folio, off, vi->tree_params.zero_digest, + vi->tree_params.digest_size); +} +EXPORT_SYMBOL_GPL (fsverity_fill_zerohash);
include/linux/fsverity.h +8 -0
@@ -201,6 +201,8 @@ bool fsverity_verify_blocks(struct fsverity_info *vi, struct folio *folio, size_t len, size_t offset);void fsverity_verify_bio (struct fsverity_info *vi,struct bio *bio);void fsverity_enqueue_verify_work (struct work_struct *work); +void fsverity_fill_zerohash (struct folio *folio,size_t offset,size_t len, +struct fsverity_info *vi);#else /* !CONFIG_FS_VERITY */
@@ -281,6 +283,12 @@ static inline void fsverity_enqueue_verify_work(struct work_struct *work)WARN_ON_ONCE (1 ); } +static inline void fsverity_fill_zerohash (struct folio *folio,size_t offset, +size_t len,struct fsverity_info *vi) +{ +WARN_ON_ONCE (1 ); +} +#endif /* !CONFIG_FS_VERITY */ static inline bool fsverity_verify_folio(struct fsverity_info *vi,
Signature · 1 line
2.51.2
PATCH v10 5/22 fsverity: pass digest size and hash of the all-zeroes block to ->write
In reply to Andrey AlbershteynLet filesystem iterate over hashes in the block and check if these are hashes of zeroed data blocks. XFS will use this to decide if it want to store tree block full of these hashes.
--- fs/btrfs/verity.c | 6 +++++- fs/ext4/verity.c | 4 +++- fs/f2fs/verity.c | 4 +++- fs/verity/enable.c | 4 +++- include/linux/fsverity.h | 6 +++++- 5 files changed, 19 insertions(+), 5 deletions(-)
fs/btrfs/verity.c +5 -1
@@ -773,11 +773,15 @@ static struct page *btrfs_read_merkle_tree_page(struct inode *inode,* @buf: Merkle tree block to write * @pos: the position of the block in the Merkle tree (in bytes) * @size: the Merkle tree block size (in bytes) +* @zero_digest: the hash of the all-zeroes block +* @digest_size: size of zero_digest, in bytes * * Returns 0 on success or negative error code on failure */ static int btrfs_write_merkle_tree_block (struct file *file,const void *buf, -u64 pos,unsigned int size) +u64 pos,unsigned int size, +const u8 *zero_digest, +unsigned int digest_size) {struct inode *inode =file_inode (file);loff_t merkle_pos =merkle_file_pos (inode);
fs/ext4/verity.c +3 -1
@@ -374,7 +374,9 @@ static void ext4_readahead_merkle_tree(struct inode *inode, pgoff_t index, }static int ext4_write_merkle_tree_block (struct file *file,const void *buf, -u64 pos,unsigned int size) +u64 pos,unsigned int size, +const u8 *zero_digest, +unsigned int digest_size) { pos +=ext4_verity_metadata_pos (file_inode (file));
fs/f2fs/verity.c +3 -1
@@ -270,7 +270,9 @@ static void f2fs_readahead_merkle_tree(struct inode *inode, pgoff_t index, }static int f2fs_write_merkle_tree_block (struct file *file,const void *buf, -u64 pos,unsigned int size) +u64 pos,unsigned int size, +const u8 *zero_digest, +unsigned int digest_size) { pos +=f2fs_verity_metadata_pos (file_inode (file));
fs/verity/enable.c +3 -1
@@ -50,7 +50,9 @@ static int write_merkle_tree_block(struct file *file, const u8 *buf,int err; err = inode->i_sb->s_vop->write_merkle_tree_block (file, buf, pos, - params->block_size); + params->block_size, + params->zero_digest, + params->digest_size);if (err)fsverity_err (inode,"Error %d writing Merkle tree block %lu" , err, index);
include/linux/fsverity.h +5 -1
@@ -124,6 +124,8 @@ struct fsverity_operations {* @buf: the Merkle tree block to write * @pos: the position of the block in the Merkle tree (in bytes) * @size: the Merkle tree block size (in bytes) +* @zero_digest: the hash of the all-zeroes block +* @digest_size: size of zero_digest, in bytes * * This is only called between ->begin_enable_verity() and * ->end_enable_verity().
@@ -131,7 +133,9 @@ struct fsverity_operations {* Return: 0 on success, -errno on failure */ int (*write_merkle_tree_block)(struct file *file,const void *buf, -u64 pos,unsigned int size); +u64 pos,unsigned int size, +const u8 *zero_digest, +unsigned int digest_size); };#ifdef CONFIG_FS_VERITY
Signature · 1 line
2.51.2
PATCH v10 6/22 fsverity: hoist pagecache_read from f2fs/ext4 to fsverity
In reply to Andrey AlbershteynThis is the same function to read from pageache. XFS will also need this, so move this to core fsverity.
Note that f2fs and ext4 functions diverged a bit, as ext4 operated over folios and f2fs operated over pages. The common one will operate over folios.
--- fs/ext4/verity.c | 32 +++----------------------------- fs/f2fs/verity.c | 30 +----------------------------- fs/verity/pagecache.c | 33 +++++++++++++++++++++++++++++++++ include/linux/fsverity.h | 2 ++ 4 files changed, 39 insertions(+), 58 deletions(-)
fs/ext4/verity.c +3 -29
@@ -34,32 +34,6 @@ static inline loff_t ext4_verity_metadata_pos(const struct inode *inode)return round_up (inode->i_size,65536 ); } -/* -* Read some verity metadata from the inode. __vfs_read() can't be used because -* we need to read beyond i_size. -*/ -static int pagecache_read (struct inode *inode,void *buf,size_t count, -loff_t pos) -{ -while (count) { -struct folio *folio; -size_t n; - - folio =read_mapping_folio (inode->i_mapping, pos >>PAGE_SHIFT , -NULL ); -if (IS_ERR (folio)) -return PTR_ERR (folio); - - n =memcpy_from_file_folio (buf, folio, pos, count); -folio_put (folio); - - buf += n; - pos += n; - count -= n; - } -return 0 ; -} -/* * Write some verity metadata to the inode for FS_IOC_ENABLE_VERITY. * kernel_write() can't be used because the file descriptor is readonly.
@@ -311,8 +285,8 @@ static int ext4_get_verity_descriptor_location(struct inode *inode, goto bad; desc_size_pos -=sizeof (desc_size_disk); - err =pagecache_read (inode, &desc_size_disk,sizeof (desc_size_disk), - desc_size_pos); + err =fsverity_pagecache_read (inode, &desc_size_disk, +sizeof (desc_size_disk), desc_size_pos);if (err)return err; desc_size =le32_to_cpu (desc_size_disk);
@@ -352,7 +326,7 @@ static int ext4_get_verity_descriptor(struct inode *inode, void *buf,if (buf_size) {if (desc_size > buf_size)return -ERANGE ; - err =pagecache_read (inode, buf, desc_size, desc_pos); + err =fsverity_pagecache_read (inode, buf, desc_size, desc_pos);if (err)return err; }
fs/f2fs/verity.c +1 -29
@@ -36,34 +36,6 @@ static inline loff_t f2fs_verity_metadata_pos(const struct inode *inode)return round_up (inode->i_size,65536 ); } -/* -* Read some verity metadata from the inode. __vfs_read() can't be used because -* we need to read beyond i_size. -*/ -static int pagecache_read (struct inode *inode,void *buf,size_t count, -loff_t pos) -{ -while (count) { -size_t n =min_t (size_t, count, -PAGE_SIZE -offset_in_page (pos)); -struct page *page; - - page =read_mapping_page (inode->i_mapping, pos >>PAGE_SHIFT , -NULL ); -if (IS_ERR (page)) -return PTR_ERR (page); - -memcpy_from_page (buf, page,offset_in_page (pos), n); - -put_page (page); - - buf += n; - pos += n; - count -= n; - } -return 0 ; -} -/* * Write some verity metadata to the inode for FS_IOC_ENABLE_VERITY. * kernel_write() can't be used because the file descriptor is readonly.
@@ -248,7 +220,7 @@ static int f2fs_get_verity_descriptor(struct inode *inode, void *buf,if (buf_size) {if (size > buf_size)return -ERANGE ; - res =pagecache_read (inode, buf, size, pos); + res =fsverity_pagecache_read (inode, buf, size, pos);if (res)return res; }
fs/verity/pagecache.c +33 -0
@@ -78,3 +78,36 @@ void fsverity_fill_zerohash(struct folio *folio, size_t offset, size_t len, vi->tree_params.digest_size); }EXPORT_SYMBOL_GPL (fsverity_fill_zerohash); + +/** +* fsverity_pagecache_read() - read page and copy data to buffer +* @inode: copy from this inode's address space +* @buf: buffer to copy to +* @count: number of bytes to copy +* @pos: position of the folio to copy from +* +* Read some verity metadata from the inode. __vfs_read() can't be used because +* we need to read beyond i_size. +*/ +int fsverity_pagecache_read (struct inode *inode,void *buf,size_t count, +loff_t pos) +{ +while (count) { +struct folio *folio; +size_t n; + + folio =read_mapping_folio (inode->i_mapping, pos >>PAGE_SHIFT , +NULL ); +if (IS_ERR (folio)) +return PTR_ERR (folio); + + n =memcpy_from_file_folio (buf, folio, pos, count); +folio_put (folio); + + buf += n; + pos += n; + count -= n; + } +return 0 ; +} +EXPORT_SYMBOL_GPL (fsverity_pagecache_read);
include/linux/fsverity.h +2 -0
@@ -328,5 +328,7 @@ void fsverity_cleanup_inode(struct inode *inode);struct page *generic_read_merkle_tree_page (struct inode *inode,pgoff_t index);void generic_readahead_merkle_tree (struct inode *inode,pgoff_t index,unsigned long nr_pages); +int fsverity_pagecache_read (struct inode *inode,void *buf,size_t count, +loff_t pos);#endif /* _LINUX_FSVERITY_H */
Signature · 1 line
2.51.2
PATCH v10 7/22 iomap: introduce IOMAP_F_FSVERITY and teach writeback to handle fsverity
In reply to Andrey AlbershteynThis flag indicates that I/O is for fsverity metadata.
In the write path skip i_size check and i_size updates as metadata is past EOF. In writeback don't update i_size and continue writeback if even folio is beyond EOF. In read path don't zero fsverity folios, again they are past EOF.
The iomap_block_needs_zeroing() is also called from write path. For folios of larger order we don't want to zero out pages in the folio as these could contain other merkle tree blocks. For fsverity, filesystem will request to read PAGE_SIZE memory regions. For data folios, iomap will zero the rest of the folio for anything which is beyond EOF. We don't want this for fsverity folios.
--- fs/iomap/buffered-io.c | 43 +++++++++++++++++++++++++++++++++--------- fs/iomap/trace.h | 3 ++- include/linux/iomap.h | 8 ++++++++ 3 files changed, 44 insertions(+), 10 deletions(-)
fs/iomap/buffered-io.c +34 -9
@@ -353,9 +353,26 @@ static inline bool iomap_block_needs_zeroing(const struct iomap_iter *iter, {const struct iomap *srcmap =iomap_iter_srcmap (iter); -return srcmap->type !=IOMAP_MAPPED || - (srcmap->flags &IOMAP_F_NEW ) || - pos >=i_size_read (iter->inode); +/* +* If this block has not been written, there's nothing to read +*/ +if (srcmap->type !=IOMAP_MAPPED ) +return true; + +/* +* Newly allocated blocks have not been written +*/ +if (srcmap->flags &IOMAP_F_NEW ) +return true; + +/* +* fsverity metadata is stored past i_size, we need to read it instead +* of zeroing +*/ +if (srcmap->flags &IOMAP_F_FSVERITY ) +return false; + +return pos >=i_size_read (iter->inode); }/**
@@ -1167,13 +1184,14 @@ static int iomap_write_iter(struct iomap_iter *iter, struct iov_iter *i,* unlock and release the folio. */ old_size = iter->inode->i_size; -if (pos + written > old_size) { +if (pos + written > old_size && + !(iter->iomap.flags &IOMAP_F_FSVERITY )) {i_size_write (iter->inode, pos + written); iter->iomap.flags |=IOMAP_F_SIZE_CHANGED ; }__iomap_put_folio (iter, write_ops, written, folio); -if (old_size < pos) +if (old_size < pos && !(iter->iomap.flags &IOMAP_F_FSVERITY ))pagecache_isize_extended (iter->inode, old_size, pos);cond_resched ();
@@ -1797,13 +1815,20 @@ static int iomap_writeback_range(struct iomap_writepage_ctx *wpc,* Check interaction of the folio with the file end. * * If the folio is entirely beyond i_size, return false. If it straddles -* i_size, adjust end_pos and zero all data beyond i_size. +* i_size, adjust end_pos and zero all data beyond i_size. Don't skip fsverity +* folios as those are beyond i_size. */ -static bool iomap_writeback_handle_eof (struct folio *folio,struct inode *inode, -u64 *end_pos) +static bool iomap_writeback_handle_eof (struct folio *folio, +struct iomap_writepage_ctx *wpc,u64 *end_pos) { +struct inode *inode = wpc->inode;u64 isize =i_size_read (inode); +if (wpc->iomap.flags &IOMAP_F_FSVERITY ) { +WARN_ON_ONCE (folio_pos (folio) < isize); +return true; + } +if (*end_pos > isize) {size_t poff =offset_in_folio (folio, isize);pgoff_t end_index = isize >>PAGE_SHIFT ;
@@ -1869,7 +1894,7 @@ int iomap_writeback_folio(struct iomap_writepage_ctx *wpc, struct folio *folio)trace_iomap_writeback_folio (inode, pos,folio_size (folio)); -if (!iomap_writeback_handle_eof (folio, inode, &end_pos)) +if (!iomap_writeback_handle_eof (folio, wpc, &end_pos))return 0 ;WARN_ON_ONCE (end_pos <= pos);
fs/iomap/trace.h +2 -1
@@ -118,7 +118,8 @@ DEFINE_RANGE_EVENT(iomap_zero_iter); { IOMAP_F_ATOMIC_BIO, "ATOMIC_BIO" }, \ { IOMAP_F_PRIVATE, "PRIVATE" }, \ { IOMAP_F_SIZE_CHANGED, "SIZE_CHANGED" }, \ - { IOMAP_F_STALE, "STALE" } + { IOMAP_F_STALE, "STALE" }, \ + { IOMAP_F_FSVERITY, "FSVERITY" } #define IOMAP_DIO_STRINGS \
include/linux/iomap.h +8 -0
@@ -87,6 +87,14 @@ struct vm_fault;#define IOMAP_F_INTEGRITY 0#endif /* CONFIG_BLK_DEV_INTEGRITY */ +/* +* Indicates reads and writes of fsverity metadata. +* +* Fsverity metadata is stored after the regular file data and thus beyond +* i_size. +*/ +#define IOMAP_F_FSVERITY (1U << 10) +/* * Flag reserved for file system specific usage */
Signature · 1 line
2.51.2
PATCH v10 8/22 iomap: teach iomap to read files with fsverity
In reply to Andrey AlbershteynObtain 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.
--- fs/iomap/buffered-io.c | 41 +++++++++++++++++++++++++++++++++++++++-- fs/iomap/ioend.c | 1 + include/linux/iomap.h | 2 ++ 3 files changed, 42 insertions(+), 2 deletions(-)
fs/iomap/buffered-io.c +39 -2
@@ -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);
fs/iomap/ioend.c +1 -0
@@ -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; }
include/linux/iomap.h +2 -0
@@ -435,6 +435,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! */ };
@@ -509,6 +510,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 {
Signature · 1 line
2.51.2
PATCH v10 9/22 iomap: introduce iomap_fsverity_write() for writing fsverity metadata
In reply to Andrey AlbershteynThis is just a wrapper around iomap_file_buffered_write() to create necessary iterator over metadata.
--- fs/iomap/buffered-io.c | 25 +++++++++++++++++++++++++ include/linux/iomap.h | 3 +++ 2 files changed, 28 insertions(+)
fs/iomap/buffered-io.c +25 -0
@@ -1287,6 +1287,31 @@ iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *i, }EXPORT_SYMBOL_GPL (iomap_file_buffered_write); +int iomap_fsverity_write (struct file *file,loff_t pos,size_t length, +const void *buf,const struct iomap_ops *ops, +const struct iomap_write_ops *write_ops) +{ +int ret; +struct iov_iter iiter; +struct kvec kvec = { + .iov_base = (void *)buf, + .iov_len = length, + }; +struct kiocb iocb = { + .ki_filp = file, + .ki_ioprio =get_current_ioprio (), + .ki_pos = pos, + }; + +iov_iter_kvec (&iiter,WRITE , &kvec,1 , length); + + ret =iomap_file_buffered_write (&iocb, &iiter, ops, write_ops,NULL ); +if (ret <0 ) +return ret; +return ret == length ?0 : -EIO ; +} +EXPORT_SYMBOL_GPL (iomap_fsverity_write); +static void iomap_write_delalloc_ifs_punch (struct inode *inode,struct folio *folio,loff_t start_byte,loff_t end_byte,struct iomap *iomap,iomap_punch_t punch)
include/linux/iomap.h +3 -0
@@ -359,6 +359,9 @@ static inline bool iomap_want_unshare_iter(const struct iomap_iter *iter)ssize_t iomap_file_buffered_write (struct kiocb *iocb,struct iov_iter *from,const struct iomap_ops *ops,const struct iomap_write_ops *write_ops,void *private); +int iomap_fsverity_write (struct file *file,loff_t pos,size_t length, +const void *buf,const struct iomap_ops *ops, +const struct iomap_write_ops *write_ops);void iomap_read_folio (const struct iomap_ops *ops,struct iomap_read_folio_ctx *ctx,void *private); void iomap_readahead(const struct iomap_ops *ops,
Signature · 1 line
2.51.2
PATCH v10 10/22 xfs: introduce fsverity on-disk changes
In reply to Andrey AlbershteynIntroduce XFS_DIFLAG2_VERITY for inodes with fsverity. This flag indicates that inode has fs-verity enabled (i.e. descriptor exist, tree is built and file is read-only).
Introduce XFS_SB_FEAT_RO_COMPAT_VERITY for filesystems having fsverity inodes. As on-disk changes applies to fsverity inodes only, let older kernels read-only access. This will be enabled in the further patch after full fsverity support.
--- fs/xfs/libxfs/xfs_format.h | 30 +++++++++++++++++++++++++++++- fs/xfs/libxfs/xfs_inode_buf.c | 8 ++++++++ fs/xfs/libxfs/xfs_inode_util.c | 2 ++ fs/xfs/libxfs/xfs_sb.c | 2 ++ fs/xfs/xfs_iops.c | 2 ++ fs/xfs/xfs_mount.h | 2 ++ 6 files changed, 45 insertions(+), 1 deletion(-)
fs/xfs/libxfs/xfs_format.h +29 -1
@@ -374,6 +374,7 @@ xfs_sb_has_compat_feature(#define XFS_SB_FEAT_RO_COMPAT_RMAPBT (1 << 1)/* reverse map btree */ #define XFS_SB_FEAT_RO_COMPAT_REFLINK (1 << 2)/* reflinked files */ #define XFS_SB_FEAT_RO_COMPAT_INOBTCNT (1 << 3)/* inobt block counts */ +#define XFS_SB_FEAT_RO_COMPAT_VERITY (1 << 4)/* fs-verity */ #define XFS_SB_FEAT_RO_COMPAT_ALL \ (XFS_SB_FEAT_RO_COMPAT_FINOBT | \ XFS_SB_FEAT_RO_COMPAT_RMAPBT | \
@@ -1230,16 +1231,21 @@ static inline void xfs_dinode_put_rdev(struct xfs_dinode *dip, xfs_dev_t rdev)*/ #define XFS_DIFLAG2_METADATA_BIT 5 +/* inodes sealed with fs-verity */ +#define XFS_DIFLAG2_VERITY_BIT 6 +#define XFS_DIFLAG2_DAX (1ULL << XFS_DIFLAG2_DAX_BIT)#define XFS_DIFLAG2_REFLINK (1ULL << XFS_DIFLAG2_REFLINK_BIT)#define XFS_DIFLAG2_COWEXTSIZE (1ULL << XFS_DIFLAG2_COWEXTSIZE_BIT)#define XFS_DIFLAG2_BIGTIME (1ULL << XFS_DIFLAG2_BIGTIME_BIT)#define XFS_DIFLAG2_NREXT64 (1ULL << XFS_DIFLAG2_NREXT64_BIT)#define XFS_DIFLAG2_METADATA (1ULL << XFS_DIFLAG2_METADATA_BIT) +#define XFS_DIFLAG2_VERITY (1ULL << XFS_DIFLAG2_VERITY_BIT)#define XFS_DIFLAG2_ANY \ (XFS_DIFLAG2_DAX | XFS_DIFLAG2_REFLINK | XFS_DIFLAG2_COWEXTSIZE | \ - XFS_DIFLAG2_BIGTIME | XFS_DIFLAG2_NREXT64 | XFS_DIFLAG2_METADATA) + XFS_DIFLAG2_BIGTIME | XFS_DIFLAG2_NREXT64 | XFS_DIFLAG2_METADATA | \ + XFS_DIFLAG2_VERITY)static inline bool xfs_dinode_has_bigtime (const struct xfs_dinode *dip) {
@@ -2021,4 +2027,26 @@ struct xfs_acl {#define SGI_ACL_FILE_SIZE (sizeof(SGI_ACL_FILE)-1)#define SGI_ACL_DEFAULT_SIZE (sizeof(SGI_ACL_DEFAULT)-1) +/* +* At maximum of 8 levels with 128 hashes per block (32 bytes SHA-256) maximum +* tree size is ((128^8 − 1)/(128 − 1)) = 567*10^12 blocks. This should fit in +* 53 bits address space. +* +* At this Merkle tree size we can cover 295EB large file. This is much larger +* than the currently supported file size. +* +* For sha512 the largest file we can cover ends at 1 << 50 offset, this is also +* good. +*/ +#define XFS_FSVERITY_LARGEST_FILE ((loff_t)1ULL << 53) + +/* +* Alignment of the fsverity metadata placement. This is largest supported PAGE +* SIZE for fsverity. This is used to space out data and metadata in page cache. +* The spacing is necessary for non-exposure of metadata to userspace and +* correct merkle tree synethesis in the iomap. +*/ +#define XFS_FSVERITY_START_ALIGN (65536) + +#endif /* __XFS_FORMAT_H__ */
fs/xfs/libxfs/xfs_inode_buf.c +8 -0
@@ -760,6 +760,14 @@ xfs_dinode_verify( !xfs_has_rtreflink(mp))return __this_address; +/* only regular files can have fsverity */ +if (flags2 &XFS_DIFLAG2_VERITY ) { +if (!xfs_has_verity (mp)) +return __this_address; +if (!S_ISREG (mode)) +return __this_address; + } +if (xfs_has_zoned (mp) && dip->di_metatype ==cpu_to_be16 (XFS_METAFILE_RTRMAP )) {if (be32_to_cpu (dip->di_used_blocks) > mp->m_sb.sb_rgextents)
fs/xfs/libxfs/xfs_inode_util.c +2 -0
@@ -126,6 +126,8 @@ xfs_ip2xflags( flags |=FS_XFLAG_DAX ;if (ip->i_diflags2 &XFS_DIFLAG2_COWEXTSIZE ) flags |=FS_XFLAG_COWEXTSIZE ; +if (ip->i_diflags2 &XFS_DIFLAG2_VERITY ) + flags |=FS_XFLAG_VERITY ; }if (xfs_inode_has_attr_fork (ip))
fs/xfs/libxfs/xfs_sb.c +2 -0
@@ -165,6 +165,8 @@ xfs_sb_version_to_features( features |=XFS_FEAT_REFLINK ;if (sbp->sb_features_ro_compat &XFS_SB_FEAT_RO_COMPAT_INOBTCNT ) features |=XFS_FEAT_INOBTCNT ; +if (sbp->sb_features_ro_compat &XFS_SB_FEAT_RO_COMPAT_VERITY ) + features |=XFS_FEAT_VERITY ;if (sbp->sb_features_incompat &XFS_SB_FEAT_INCOMPAT_FTYPE ) features |=XFS_FEAT_FTYPE ;if (sbp->sb_features_incompat &XFS_SB_FEAT_INCOMPAT_SPINODES )
fs/xfs/xfs_iops.c +2 -0
@@ -1398,6 +1398,8 @@ xfs_diflags_to_iflags( flags |=S_NOATIME ;if (init &&xfs_inode_should_enable_dax (ip)) flags |=S_DAX ; +if (xflags &FS_XFLAG_VERITY ) + flags |=S_VERITY ;/* * S_DAX can only be set during inode initialization and is never set by
fs/xfs/xfs_mount.h +2 -0
@@ -388,6 +388,7 @@ typedef struct xfs_mount {#define XFS_FEAT_EXCHANGE_RANGE (1ULL << 27)/* exchange range */ #define XFS_FEAT_METADIR (1ULL << 28)/* metadata directory tree */ #define XFS_FEAT_ZONED (1ULL << 29)/* zoned RT device */ +#define XFS_FEAT_VERITY (1ULL << 30)/* fs-verity */ /* Mount features */ #define XFS_FEAT_NOLIFETIME (1ULL << 47)/* disable lifetime hints */
@@ -445,6 +446,7 @@ __XFS_HAS_FEAT(exchange_range, EXCHANGE_RANGE) __XFS_HAS_FEAT(metadir, METADIR) __XFS_HAS_FEAT(zoned, ZONED) __XFS_HAS_FEAT(nolifetime, NOLIFETIME) +__XFS_HAS_FEAT(verity, VERITY)static inline bool xfs_has_rtgroups (const struct xfs_mount *mp) {
Signature · 1 line
2.51.2
PATCH v10 11/22 xfs: initialize fs-verity on file open
In reply to Andrey Albershteynfs-verity will read and attach metadata (not the tree itself) from a disk for those inodes which already have fs-verity enabled.
--- fs/xfs/xfs_file.c | 8 ++++++++ 1 file changed, 8 insertions(+)
fs/xfs/xfs_file.c +8 -0
@@ -37,6 +37,7 @@#include <linux/fadvise.h> #include <linux/mount.h> #include <linux/filelock.h> +#include <linux/fsverity.h> static const struct vm_operations_struct xfs_file_vm_ops;
@@ -1700,11 +1701,18 @@ xfs_file_open(struct inode *inode, struct file *file) { + int error; +if (xfs_is_shutdown (XFS_M (inode->i_sb)))return -EIO ; file->f_mode |=FMODE_NOWAIT |FMODE_CAN_ODIRECT ;if (xfs_get_atomic_write_min (XFS_I (inode)) >0 ) file->f_mode |=FMODE_CAN_ATOMIC_WRITE ; + + error =fsverity_file_open (inode, file); +if (error) +return error; +return generic_file_open (inode, file); }
Signature · 1 line
2.51.2
PATCH v10 12/22 xfs: don't allow to enable DAX on fs-verity sealed inode
In reply to Andrey Albershteynfs-verity doesn't support DAX. Forbid filesystem to enable DAX on inodes which already have fs-verity enabled. The opposite is checked when fs-verity is enabled, it won't be enabled if DAX is.
--- fs/xfs/xfs_iops.c | 2 ++ 1 file changed, 2 insertions(+)
fs/xfs/xfs_iops.c +2 -0
@@ -1370,6 +1370,8 @@ xfs_inode_should_enable_dax(return false;if (!xfs_inode_supports_dax (ip))return false; +if (ip->i_diflags2 &XFS_DIFLAG2_VERITY ) +return false;if (xfs_has_dax_always (ip->i_mount))return true;if (ip->i_diflags2 &XFS_DIFLAG2_DAX )
Signature · 1 line
2.51.2
PATCH v10 13/22 xfs: disable direct read path for fs-verity files
In reply to Andrey AlbershteynThe direct path is not supported on verity files. Attempts to use direct I/O path on such files should fall back to buffered I/O path.
--- fs/xfs/xfs_file.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
fs/xfs/xfs_file.c +10 -1
@@ -282,7 +282,8 @@ xfs_file_dax_read(struct kiocb *iocb, struct iov_iter *to) { - struct xfs_inode *ip = XFS_I(iocb->ki_filp->f_mapping->host); + struct inode *inode = iocb->ki_filp->f_mapping->host; +struct xfs_inode *ip =XFS_I (inode);ssize_t ret =0 ;trace_xfs_file_dax_read (iocb, to);
@@ -333,6 +334,14 @@ xfs_file_read_iter(if (xfs_is_shutdown (mp))return -EIO ; +/* +* In case fs-verity is enabled, we also fallback to the buffered read +* from the direct read path. Therefore, IOCB_DIRECT is set and need to +* be cleared (see generic_file_read_iter()) +*/ +if (fsverity_active (inode)) + iocb->ki_flags &= ~IOCB_DIRECT ; +if (IS_DAX (inode)) ret =xfs_file_dax_read (iocb, to);else if (iocb->ki_flags &IOCB_DIRECT )
Signature · 1 line
2.51.2
PATCH v10 14/22 xfs: handle fsverity I/O in write/read path
In reply to Andrey AlbershteynFor write/writeback set IOMAP_F_FSVERITY flag telling iomap to not update inode size and to not skip folios beyond EOF.
Initiate fsverity writeback with IOMAP_F_FSVERITY set to tell iomap should not skip folio that is dirty beyond EOF.
In read path let iomap know that we are reading fsverity metadata. So, treat holes in the tree as request to synthesize tree blocks and hole after descriptor as end of the fsverity region.
Introduce a new inode flag meaning that merkle tree is being build on the inode.
--- fs/xfs/Makefile | 1 + fs/xfs/libxfs/xfs_bmap.c | 7 +++++++ fs/xfs/xfs_aops.c | 16 +++++++++++++++- fs/xfs/xfs_fsverity.c | 21 +++++++++++++++++++++ fs/xfs/xfs_fsverity.h | 20 ++++++++++++++++++++ fs/xfs/xfs_inode.h | 6 ++++++ fs/xfs/xfs_iomap.c | 15 +++++++++++++-- 7 files changed, 83 insertions(+), 3 deletions(-) create mode 100644 fs/xfs/xfs_fsverity.c create mode 100644 fs/xfs/xfs_fsverity.h
fs/xfs/Makefile +1 -0
@@ -149,6 +149,7 @@ xfs-$(CONFIG_XFS_POSIX_ACL) += xfs_acl.o xfs-$(CONFIG_SYSCTL) += xfs_sysctl.o xfs-$(CONFIG_COMPAT) += xfs_ioctl32.o xfs-$(CONFIG_EXPORTFS_BLOCK_OPS) += xfs_pnfs.o +xfs-$(CONFIG_FS_VERITY) += xfs_fsverity.o # notify failure ifeq ($(CONFIG_MEMORY_FAILURE),y)
fs/xfs/libxfs/xfs_bmap.c +7 -0
@@ -41,6 +41,8 @@#include "xfs_inode_util.h" #include "xfs_rtgroup.h" #include "xfs_zone_alloc.h" +#include "xfs_fsverity.h" +#include <linux/fsverity.h> struct kmem_cache *xfs_bmap_intent_cache;
@@ -4451,6 +4453,11 @@ xfs_bmapi_convert_one_delalloc(XFS_STATS_ADD (mp, xs_xstrat_bytes,XFS_FSB_TO_B (mp, bma.length));XFS_STATS_INC (mp, xs_xstrat_quick); +if (xfs_iflags_test (ip,XFS_VERITY_CONSTRUCTION ) && +XFS_FSB_TO_B (mp, bma.got.br_startoff) >= +xfs_fsverity_metadata_offset (ip)) + flags |=IOMAP_F_FSVERITY ; +ASSERT (!isnullstartblock (bma.got.br_startblock));xfs_bmbt_to_iomap (ip, iomap, &bma.got,0 , flags,xfs_iomap_inode_sequence (ip, flags));
fs/xfs/xfs_aops.c +15 -1
@@ -22,6 +22,7 @@#include "xfs_icache.h" #include "xfs_zone_alloc.h" #include "xfs_rtgroup.h" +#include "xfs_fsverity.h" #include <linux/bio-integrity.h> struct xfs_writepage_ctx {
@@ -339,12 +340,16 @@ xfs_map_blocks(int retries =0 ;int error =0 ;unsigned int *seq; +unsigned int iomap_flags =0 ;if (xfs_is_shutdown (mp))return -EIO ;XFS_ERRORTAG_DELAY (mp,XFS_ERRTAG_WB_DELAY_MS ); +if (xfs_iflags_test (ip,XFS_VERITY_CONSTRUCTION )) + iomap_flags |=IOMAP_F_FSVERITY ; +/* * COW fork blocks can overlap data fork blocks even if the blocks * aren't shared. COW I/O always takes precedent, so we must always
@@ -432,7 +437,8 @@ xfs_map_blocks( isnullstartblock(imap.br_startblock)) goto allocate_blocks; -xfs_bmbt_to_iomap (ip, &wpc->iomap, &imap,0 ,0 ,XFS_WPC (wpc)->data_seq); +xfs_bmbt_to_iomap (ip, &wpc->iomap, &imap,0 , iomap_flags, +XFS_WPC (wpc)->data_seq);trace_xfs_map_blocks_found (ip, offset, count, whichfork, &imap);return 0 ; allocate_blocks:
@@ -705,6 +711,14 @@ xfs_vm_writepages( }, }; +/* +* Writeback does not work for folios past EOF, let it know that +* I/O happens for fsverity metadata and this restriction need +* to be skipped +*/ +if (xfs_iflags_test (ip,XFS_VERITY_CONSTRUCTION )) + wpc.ctx.iomap.flags |=IOMAP_F_FSVERITY ; +return iomap_writepages (&wpc.ctx); } }
fs/xfs/xfs_fsverity.c new file +21 -0
@@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (C) 2026 Red Hat, Inc. +*/ +#include "xfs_platform.h" +#include "xfs_format.h" +#include "xfs_inode.h" +#include "xfs_shared.h" +#include "xfs_trans_resv.h" +#include "xfs_mount.h" +#include "xfs_fsverity.h" +#include "xfs_fsverity.h" +#include <linux/fsverity.h> +#include <linux/iomap.h> + +loff_t +xfs_fsverity_metadata_offset ( +const struct xfs_inode *ip) +{ +return round_up (i_size_read (VFS_IC (ip)),XFS_FSVERITY_START_ALIGN ); +}
fs/xfs/xfs_fsverity.h new file +20 -0
@@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (C) 2026 Red Hat, Inc. +*/ +#ifndef __XFS_FSVERITY_H__ +#define __XFS_FSVERITY_H__ + +#include "xfs_platform.h" + +#ifdef CONFIG_FS_VERITY +loff_t xfs_fsverity_metadata_offset (const struct xfs_inode *ip); +#else +static inline loff_t xfs_fsverity_metadata_offset (const struct xfs_inode *ip) +{ +WARN_ON_ONCE (1 ); +return ULLONG_MAX ; +} +#endif /* CONFIG_FS_VERITY */ + +#endif /* __XFS_FSVERITY_H__ */
fs/xfs/xfs_inode.h +6 -0
@@ -415,6 +415,12 @@ static inline bool xfs_inode_can_sw_atomic_write(const struct xfs_inode *ip)*/ #define XFS_IREMAPPING (1U << 15) +/* +* fs-verity's Merkle tree is under construction. The file is read-only, the +* only writes happening are for the fsverity metadata. +*/ +#define XFS_VERITY_CONSTRUCTION (1U << 16) +/* All inode state flags related to inode reclaim. */ #define XFS_ALL_IRECLAIM_FLAGS (XFS_IRECLAIMABLE | \ XFS_IRECLAIM | \
fs/xfs/xfs_iomap.c +13 -2
@@ -32,6 +32,8 @@#include "xfs_rtbitmap.h" #include "xfs_icache.h" #include "xfs_zone_alloc.h" +#include "xfs_fsverity.h" +#include <linux/fsverity.h> #define XFS_ALLOC_ALIGN (mp, off) \ (((off) >> mp->m_allocsize_log) << mp->m_allocsize_log)
@@ -1812,6 +1814,9 @@ xfs_buffered_write_iomap_begin(return xfs_direct_write_iomap_begin (inode, offset, count, flags, iomap, srcmap); +if (xfs_iflags_test (ip,XFS_VERITY_CONSTRUCTION )) + iomap_flags |=IOMAP_F_FSVERITY ; + error =xfs_qm_dqattach (ip);if (error)return error;
@@ -2191,12 +2196,17 @@ xfs_read_iomap_begin(bool shared = false;unsigned int lockmode =XFS_ILOCK_SHARED ;u64 seq; +unsigned int iomap_flags =0 ;ASSERT (!(flags & (IOMAP_WRITE |IOMAP_ZERO )));if (xfs_is_shutdown (mp))return -EIO ; +if (fsverity_active (inode) && + (offset >=xfs_fsverity_metadata_offset (ip))) + iomap_flags |=IOMAP_F_FSVERITY ; + error =xfs_ilock_for_iomap (ip, flags, &lockmode);if (error)return error;
@@ -2210,8 +2220,9 @@ xfs_read_iomap_begin(if (error)return error;trace_xfs_iomap_found (ip, offset, length,XFS_DATA_FORK , &imap); -return xfs_bmbt_to_iomap (ip, iomap, &imap, flags, - shared ?IOMAP_F_SHARED :0 , seq); + iomap_flags |= shared ?IOMAP_F_SHARED :0 ; + +return xfs_bmbt_to_iomap (ip, iomap, &imap, flags, iomap_flags, seq); }const struct iomap_ops xfs_read_iomap_ops = {
Signature · 1 line
2.51.2
PATCH v10 15/22 xfs: use read ioend for fsverity data verification
In reply to Andrey AlbershteynUse read ioends for fsverity verification. Do not issues fsverity metadata I/O through the same workqueue due to risk of a deadlock by a filled workqueue.
Pass fsverity_info from iomap context down to the ioend as hashtable lookups are expensive.
Add a simple helper to check that this is not fsverity metadata but file data that needs verification.
--- fs/xfs/xfs_aops.c | 46 ++++++++++++++++++++++++++++++++++--------- fs/xfs/xfs_fsverity.c | 9 +++++++++ fs/xfs/xfs_fsverity.h | 6 ++++++ 3 files changed, 52 insertions(+), 9 deletions(-)
fs/xfs/xfs_aops.c +37 -9
@@ -24,6 +24,7 @@#include "xfs_rtgroup.h" #include "xfs_fsverity.h" #include <linux/bio-integrity.h> +#include <linux/fsverity.h> struct xfs_writepage_ctx {struct iomap_writepage_ctx ctx;
@@ -171,6 +172,23 @@ xfs_end_ioend_write(memalloc_nofs_restore (nofs_flag); } +/* +* IO read completion. +*/ +static void +xfs_end_ioend_read ( +struct iomap_ioend *ioend) +{ +struct xfs_inode *ip =XFS_I (ioend->io_inode); + +if (!ioend->io_bio.bi_status && +xfs_fsverity_is_file_data (ip, ioend->io_offset)) +fsverity_verify_bio (ioend->io_vi, + &ioend->io_bio); +iomap_finish_ioends (ioend, +blk_status_to_errno (ioend->io_bio.bi_status)); +} +/* * Finish all pending IO completions that require transactional modifications. *
@@ -205,8 +223,7 @@ xfs_end_io(list_del_init (&ioend->io_list);iomap_ioend_try_merge (ioend, &tmp);if (bio_op (&ioend->io_bio) ==REQ_OP_READ ) -iomap_finish_ioends (ioend, -blk_status_to_errno (ioend->io_bio.bi_status)); +xfs_end_ioend_read (ioend);else xfs_end_ioend_write (ioend);cond_resched ();
@@ -232,9 +249,14 @@ xfs_end_bio( }spin_lock_irqsave (&ip->i_ioend_lock, flags); -if (list_empty (&ip->i_ioend_list)) -WARN_ON_ONCE (!queue_work (mp->m_unwritten_workqueue, +if (list_empty (&ip->i_ioend_list)) { +if (IS_ENABLED (CONFIG_FS_VERITY ) && ioend->io_vi && + ioend->io_offset <xfs_fsverity_metadata_offset (ip)) +fsverity_enqueue_verify_work (&ip->i_ioend_work); +else +WARN_ON_ONCE (!queue_work (mp->m_unwritten_workqueue, &ip->i_ioend_work)); + }list_add_tail (&ioend->io_list, &ip->i_ioend_list);spin_unlock_irqrestore (&ip->i_ioend_lock, flags); }
@@ -764,9 +786,13 @@ xfs_bio_submit_read( struct iomap_read_folio_ctx *ctx) {struct bio *bio = ctx->read_ctx; +struct iomap_ioend *ioend;/* defer read completions to the ioend workqueue */ -iomap_init_ioend (iter->inode, bio, ctx->read_ctx_file_offset,0 ); + ioend =iomap_init_ioend (iter->inode, bio, ctx->read_ctx_file_offset, +0 ); + ioend->io_vi = ctx->vi; + bio->bi_end_io = xfs_end_bio;submit_bio (bio); }
@@ -779,11 +805,13 @@ static const struct iomap_read_ops xfs_iomap_read_ops = {static inline const struct iomap_read_ops *xfs_get_iomap_read_ops ( -const struct address_space *mapping) +const struct address_space *mapping, +loff_t position) {struct xfs_inode *ip =XFS_I (mapping->host); -if (bdev_has_integrity_csum (xfs_inode_buftarg (ip)->bt_bdev)) +if (bdev_has_integrity_csum (xfs_inode_buftarg (ip)->bt_bdev) || +xfs_fsverity_is_file_data (ip, position))return &xfs_iomap_read_ops;return &iomap_bio_read_ops; }
@@ -795,7 +823,7 @@ xfs_vm_read_folio( {struct iomap_read_folio_ctx ctx = { .cur_folio = folio }; - ctx.ops =xfs_get_iomap_read_ops (folio->mapping); + ctx.ops =xfs_get_iomap_read_ops (folio->mapping,folio_pos (folio));iomap_read_folio (&xfs_read_iomap_ops, &ctx,NULL );return 0 ; }
@@ -806,7 +834,7 @@ xfs_vm_readahead( {struct iomap_read_folio_ctx ctx = { .rac = rac }; - ctx.ops =xfs_get_iomap_read_ops (rac->mapping), + ctx.ops =xfs_get_iomap_read_ops (rac->mapping,readahead_pos (rac));iomap_readahead (&xfs_read_iomap_ops, &ctx,NULL ); }
fs/xfs/xfs_fsverity.c +9 -0
@@ -19,3 +19,12 @@ xfs_fsverity_metadata_offset( {return round_up (i_size_read (VFS_IC (ip)),XFS_FSVERITY_START_ALIGN ); } + +bool +xfs_fsverity_is_file_data ( +const struct xfs_inode *ip, +loff_t offset) +{ +return fsverity_active (VFS_IC (ip)) && + offset <xfs_fsverity_metadata_offset (ip); +}
fs/xfs/xfs_fsverity.h +6 -0
@@ -9,12 +9,18 @@#ifdef CONFIG_FS_VERITY loff_t xfs_fsverity_metadata_offset (const struct xfs_inode *ip); +bool xfs_fsverity_is_file_data (const struct xfs_inode *ip,loff_t offset);#else static inline loff_t xfs_fsverity_metadata_offset (const struct xfs_inode *ip) {WARN_ON_ONCE (1 );return ULLONG_MAX ; } +static inline bool xfs_fsverity_is_file_data (const struct xfs_inode *ip, +loff_t offset) +{ +return false; +}#endif /* CONFIG_FS_VERITY */ #endif /* __XFS_FSVERITY_H__ */
Signature · 1 line
2.51.2
PATCH v10 16/22 xfs: add fs-verity support
In reply to Andrey AlbershteynAdd integration with fs-verity. XFS stores fs-verity descriptor and Merkle tree in the inode data fork at first block aligned to 64k past EOF.
The Merkle tree reading/writing is done through iomap interface. The data itself is read to the inode's page cache. When XFS reads from this region iomap doesn't call into fsverity to verify it against Merkle tree. For data, verification is done at ioend completion in a workqueue.
When fs-verity is enabled on an inode, the XFS_IVERITY_CONSTRUCTION flag is set meaning that the Merkle tree is being build. The initialization ends with storing of verity descriptor and setting inode on-disk flag (XFS_DIFLAG2_VERITY). Lastly, the XFS_IVERITY_CONSTRUCTION is dropped and I_VERITY is set on inode.
The descriptor is stored in a new block aligned to 64k after the last Merkle tree block. The size of the descriptor is stored at the end of the last descriptor block (descriptor can be multiple blocks).
--- fs/xfs/xfs_bmap_util.c | 8 + fs/xfs/xfs_fsverity.c | 353 ++++++++++++++++++++++++++++++++++++++++- fs/xfs/xfs_fsverity.h | 2 + fs/xfs/xfs_message.c | 4 + fs/xfs/xfs_message.h | 1 + fs/xfs/xfs_mount.h | 2 + fs/xfs/xfs_super.c | 7 + 7 files changed, 376 insertions(+), 1 deletion(-)
fs/xfs/xfs_bmap_util.c +8 -0
@@ -31,6 +31,7 @@#include "xfs_rtbitmap.h" #include "xfs_rtgroup.h" #include "xfs_zone_alloc.h" +#include <linux/fsverity.h> /* Kernel only BMAP related definitions and functions */
@@ -553,6 +554,13 @@ xfs_can_free_eofblocks(if (last_fsb <= end_fsb)return false; +/* +* Nothing to clean on fsverity inodes as they don't use prealloc and +* there no delalloc as only written data is fsverity metadata +*/ +if (IS_VERITY (VFS_I (ip))) +return false; +/* * Check if there is an post-EOF extent to free. If there are any * delalloc blocks attached to the inode (data fork delalloc
fs/xfs/xfs_fsverity.c +352 -1
369 lines not on this page · raw message
fs/xfs/xfs_fsverity.h +2 -0
@@ -6,8 +6,10 @@#define __XFS_FSVERITY_H__#include "xfs_platform.h" +#include <linux/fsverity.h> #ifdef CONFIG_FS_VERITY +extern const struct fsverity_operations xfs_fsverity_ops;loff_t xfs_fsverity_metadata_offset (const struct xfs_inode *ip);bool xfs_fsverity_is_file_data (const struct xfs_inode *ip,loff_t offset);#else
fs/xfs/xfs_message.c +4 -0
@@ -153,6 +153,10 @@ xfs_warn_experimental( .opstate = XFS_OPSTATE_WARNED_ZONED, .name = "zoned RT device", }, + [XFS_EXPERIMENTAL_FSVERITY] = { + .opstate = XFS_OPSTATE_WARNED_FSVERITY, + .name = "fsverity", + }, };ASSERT (feat >=0 && feat <XFS_EXPERIMENTAL_MAX );BUILD_BUG_ON (ARRAY_SIZE (features) !=XFS_EXPERIMENTAL_MAX );
fs/xfs/xfs_message.h +1 -0
@@ -94,6 +94,7 @@ enum xfs_experimental_feat {XFS_EXPERIMENTAL_SHRINK ,XFS_EXPERIMENTAL_LARP ,XFS_EXPERIMENTAL_ZONED , +XFS_EXPERIMENTAL_FSVERITY , XFS_EXPERIMENTAL_MAX, };
fs/xfs/xfs_mount.h +2 -0
@@ -586,6 +586,8 @@ __XFS_HAS_FEAT(nouuid, NOUUID)#define XFS_OPSTATE_WARNED_ZONED 19/* (Zoned) GC is in progress */ #define XFS_OPSTATE_ZONEGC_RUNNING 20 +/* Kernel has logged a warning about fsverity support */ +#define XFS_OPSTATE_WARNED_FSVERITY 21#define __XFS_IS_OPSTATE (name,NAME ) \ static inline bool xfs_is_ ## name (struct xfs_mount *mp) \
fs/xfs/xfs_super.c +7 -0
@@ -30,6 +30,7 @@#include "xfs_filestream.h" #include "xfs_quota.h" #include "xfs_sysfs.h" +#include "xfs_fsverity.h" #include "xfs_ondisk.h" #include "xfs_rmap_item.h" #include "xfs_refcount_item.h"
@@ -1686,6 +1687,9 @@ xfs_fs_fill_super( sb->s_quota_types =QTYPE_MASK_USR |QTYPE_MASK_GRP |QTYPE_MASK_PRJ ;#endif sb->s_op = &xfs_super_operations; +#ifdef CONFIG_FS_VERITY + sb->s_vop = &xfs_fsverity_ops; +#endif /* * Delay mount work if the debug hook is set. This is debug
@@ -1939,6 +1943,9 @@ xfs_fs_fill_super(if (error) goto out_filestream_unmount; +if (xfs_has_verity (mp)) +xfs_warn_experimental (mp,XFS_EXPERIMENTAL_FSVERITY ); + root =igrab (VFS_I (mp->m_rootip));if (!root) { error = -ENOENT ;
Signature · 1 line
2.51.2
PATCH v10 17/22 xfs: remove unwritten extents after preallocations in fsverity metadata
In reply to Andrey AlbershteynXFS preallocates spaces during writes. In normal I/O this space, if unused, is removed by truncate. For files with fsverity XFS does not use truncate as fsverity metadata is stored past EOF.
After we're done with writing fsverity metadata iterate over extents in that region and remove any unwritten ones. These would be left overs in the holes in the merkle tree and past fsverity descriptor.
--- fs/xfs/xfs_fsverity.c | 69 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+)
fs/xfs/xfs_fsverity.c +69 -0
@@ -21,6 +21,8 @@#include "xfs_iomap.h" #include "xfs_error.h" #include "xfs_health.h" +#include "xfs_bmap.h" +#include "xfs_bmap_util.h" #include <linux/fsverity.h> #include <linux/iomap.h> #include <linux/pagemap.h>
@@ -171,6 +173,65 @@ xfs_fsverity_delete_metadata(return error; } +static int +xfs_fsverity_cancel_unwritten ( +struct xfs_inode *ip, +loff_t start, +loff_t end) +{ +struct xfs_mount *mp = ip->i_mount; +struct xfs_trans *tp; +xfs_fileoff_t offset_fsb =XFS_B_TO_FSB (mp, start); +xfs_fileoff_t end_fsb =XFS_B_TO_FSB (mp, end); +struct xfs_bmbt_irec imap; +int nimaps; +int error =0 ; +int done; + + +while (offset_fsb < end_fsb) { + nimaps =1 ; + + error =xfs_trans_alloc (mp, &M_RES (mp)->tr_write,0 ,0 , +0 , &tp); +if (error) +return error; + +xfs_ilock (ip,XFS_ILOCK_EXCL ); + error =xfs_bmapi_read (ip, offset_fsb, end_fsb - offset_fsb, + &imap, &nimaps,0 ); +if (error) + goto out_cancel; + +if (nimaps ==0 ) + goto out_cancel; + +if (imap.br_state ==XFS_EXT_UNWRITTEN ) { +xfs_trans_ijoin (tp, ip,0 ); + + error =xfs_bunmapi (tp, ip, imap.br_startoff, + imap.br_blockcount,0 ,1 , &done); +if (error) + goto out_cancel; + + error =xfs_trans_commit (tp); +if (error) +return error; + }else { +xfs_trans_cancel (tp); + } +xfs_iunlock (ip,XFS_ILOCK_EXCL ); + + offset_fsb = imap.br_startoff + imap.br_blockcount; + } + +return error; +out_cancel: +xfs_trans_cancel (tp); +xfs_iunlock (ip,XFS_ILOCK_EXCL ); +return error; +} +/* * Prepare to enable fsverity by clearing old metadata.
@@ -248,6 +309,14 @@ xfs_fsverity_end_enable(if (error) goto out; +/* +* Remove unwritten extents left by COW preallocations and write +* preallocation in the merkle tree holes and past descriptor +*/ + error =xfs_fsverity_cancel_unwritten (ip, range_start,LLONG_MAX ); +if (error) + goto out; +/* * Proactively drop any delayed allocations in COW fork, the fsverity * files are read-only
Signature · 1 line
2.51.2
PATCH v10 18/22 xfs: add fs-verity ioctls
In reply to Andrey AlbershteynAdd fs-verity ioctls to enable, dump metadata (descriptor and Merkle tree pages) and obtain file's digest.
[djwong: remove unnecessary casting]
--- fs/xfs/xfs_ioctl.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
fs/xfs/xfs_ioctl.c +14 -0
@@ -49,6 +49,7 @@#include <linux/mount.h> #include <linux/fileattr.h> +#include <linux/fsverity.h> /* Return 0 on success or positive error */ int
@@ -1445,6 +1446,19 @@ xfs_file_ioctl(case XFS_IOC_VERIFY_MEDIA :return xfs_ioc_verify_media (filp, arg); +case FS_IOC_ENABLE_VERITY : +if (!xfs_has_verity (mp)) +return -EOPNOTSUPP ; +return fsverity_ioctl_enable (filp, arg); +case FS_IOC_MEASURE_VERITY : +if (!xfs_has_verity (mp)) +return -EOPNOTSUPP ; +return fsverity_ioctl_measure (filp, arg); +case FS_IOC_READ_VERITY_METADATA : +if (!xfs_has_verity (mp)) +return -EOPNOTSUPP ; +return fsverity_ioctl_read_metadata (filp, arg); +default :return -ENOTTY ; }
Signature · 1 line
2.51.2
PATCH v10 19/22 xfs: advertise fs-verity being available on filesystem
In reply to Andrey AlbershteynFrom: "Darrick J. Wong" <[email protected]>
Advertise that this filesystem supports fsverity.
--- fs/xfs/libxfs/xfs_fs.h | 1 + fs/xfs/libxfs/xfs_sb.c | 2 ++ 2 files changed, 3 insertions(+)
fs/xfs/libxfs/xfs_fs.h +1 -0
@@ -250,6 +250,7 @@ typedef struct xfs_fsop_resblks {#define XFS_FSOP_GEOM_FLAGS_PARENT (1 << 25)/* linux parent pointers */ #define XFS_FSOP_GEOM_FLAGS_METADIR (1 << 26)/* metadata directories */ #define XFS_FSOP_GEOM_FLAGS_ZONED (1 << 27)/* zoned rt device */ +#define XFS_FSOP_GEOM_FLAGS_VERITY (1 << 28)/* fs-verity */ /* * Minimum and maximum sizes need for growth checks.
fs/xfs/libxfs/xfs_sb.c +2 -0
@@ -1590,6 +1590,8 @@ xfs_fs_geometry( geo->flags |=XFS_FSOP_GEOM_FLAGS_METADIR ;if (xfs_has_zoned (mp)) geo->flags |=XFS_FSOP_GEOM_FLAGS_ZONED ; +if (xfs_has_verity (mp)) + geo->flags |=XFS_FSOP_GEOM_FLAGS_VERITY ; geo->rtsectsize = sbp->sb_blocksize; geo->dirblocksize =xfs_dir2_dirblock_bytes (sbp);
Signature · 1 line
2.51.2
PATCH v10 20/22 xfs: check and repair the verity inode flag state
In reply to Andrey AlbershteynFrom: "Darrick J. Wong" <[email protected]>
If an inode has the incore verity iflag set, make sure that we can actually activate fsverity on that inode. If activation fails due to a fsverity metadata validation error, clear the flag. The usage model for fsverity requires that any program that cares about verity state is required to call statx/getflags to check that the flag is set after opening the file, so clearing the flag will not compromise that model.
--- fs/xfs/scrub/attr.c | 7 +++++ fs/xfs/scrub/common.c | 53 +++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/common.h | 2 ++ fs/xfs/scrub/inode.c | 7 +++++ fs/xfs/scrub/inode_repair.c | 36 +++++++++++++++++++++++++ 5 files changed, 105 insertions(+)
fs/xfs/scrub/attr.c +7 -0
@@ -649,6 +649,13 @@ xchk_xattr(if (!xfs_inode_hasattr (sc->ip))return -ENOENT ; +/* +* If this is a verity file that won't activate, we cannot check the +* merkle tree geometry. +*/ +if (xchk_inode_verity_broken (sc->ip)) +xchk_set_incomplete (sc); +/* Allocate memory for xattr checking. */ error =xchk_setup_xattr_buf (sc,0 );if (error == -ENOMEM )
fs/xfs/scrub/common.c +53 -0
62 lines not on this page · raw message
fs/xfs/scrub/common.h +2 -0
@@ -266,6 +266,8 @@ int xchk_inode_is_allocated(struct xfs_scrub *sc, xfs_agino_t agino, bool *inuse);int xchk_inode_count_blocks (struct xfs_scrub *sc,int whichfork,xfs_extnum_t *nextents,xfs_filblks_t *count); +int xchk_inode_setup_verity (struct xfs_scrub *sc); +bool xchk_inode_verity_broken (struct xfs_inode *ip);bool xchk_inode_is_dirtree_root (const struct xfs_inode *ip);bool xchk_inode_is_sb_rooted (const struct xfs_inode *ip);
fs/xfs/scrub/inode.c +7 -0
@@ -36,6 +36,10 @@ xchk_prepare_iscrub(xchk_ilock (sc,XFS_IOLOCK_EXCL ); + error =xchk_inode_setup_verity (sc); +if (error) +return error; + error =xchk_trans_alloc (sc,0 );if (error)return error;
@@ -833,6 +837,9 @@ xchk_inode(if (S_ISREG (VFS_I (sc->ip)->i_mode))xchk_inode_check_reflink_iflag (sc, sc->ip->i_ino); +if (xchk_inode_verity_broken (sc->ip)) +xchk_ino_set_corrupt (sc, sc->sm->sm_ino); +xchk_inode_check_unlinked (sc);xchk_inode_xref (sc, sc->ip->i_ino, &di);
fs/xfs/scrub/inode_repair.c +36 -0
@@ -573,6 +573,8 @@ xrep_dinode_flags( dip->di_nrext64_pad =0 ; else if (dip->di_version >= 3) dip->di_v3_pad = 0; +if (!xfs_has_verity (mp) || !S_ISREG (mode)) + flags2 &= ~XFS_DIFLAG2_VERITY ;if (flags2 &XFS_DIFLAG2_METADATA ) {xfs_failaddr_t fa;
@@ -1613,6 +1615,10 @@ xrep_dinode_core(if (iget_error)return iget_error; + error =xchk_inode_setup_verity (sc); +if (error) +return error; + error =xchk_trans_alloc (sc,0 );if (error)return error;
@@ -2032,6 +2038,27 @@ xrep_inode_unlinked(return 0 ; } +/* +* If this file is a fsverity file, xchk_prepare_iscrub or xrep_dinode_core +* should have activated it. If it's still not active, then there's something +* wrong with the verity descriptor and we should turn it off. +*/ +STATIC int +xrep_inode_verity ( +struct xfs_scrub *sc) +{ +struct inode *inode =VFS_I (sc->ip); + +if (xchk_inode_verity_broken (sc->ip)) { + sc->ip->i_diflags2 &= ~XFS_DIFLAG2_VERITY ; + inode->i_flags &= ~S_VERITY ; + +xfs_trans_log_inode (sc->tp, sc->ip,XFS_ILOG_CORE ); + } + +return 0 ; +} +/* Repair an inode's fields. */ int xrep_inode(
@@ -2081,6 +2108,15 @@ xrep_inode(return error; } +/* +* Disable fsverity if it cannot be activated. Activation failure +* prohibits the file from being opened, so there cannot be another +* program with an open fd to what it thinks is a verity file. +*/ + error =xrep_inode_verity (sc); +if (error) +return error; +/* Reconnect incore unlinked list */ error =xrep_inode_unlinked (sc);if (error)
Signature · 1 line
2.51.2
PATCH v10 21/22 xfs: introduce health state for corrupted fsverity metadata
In reply to Andrey AlbershteynReport corrupted fsverity descriptor through health system.
--- fs/xfs/libxfs/xfs_fs.h | 1 + fs/xfs/libxfs/xfs_health.h | 4 +++- fs/xfs/xfs_fsverity.c | 13 ++++++++++--- fs/xfs/xfs_health.c | 1 + 4 files changed, 15 insertions(+), 4 deletions(-)
fs/xfs/libxfs/xfs_fs.h +1 -0
@@ -422,6 +422,7 @@ struct xfs_bulkstat {#define XFS_BS_SICK_SYMLINK (1 << 6)/* symbolic link remote target */ #define XFS_BS_SICK_PARENT (1 << 7)/* parent pointers */ #define XFS_BS_SICK_DIRTREE (1 << 8)/* directory tree structure */ +#define XFS_BS_SICK_FSVERITY (1 << 9)/* fsverity metadata */ /* * Project quota id helpers (previously projid was 16bit only
fs/xfs/libxfs/xfs_health.h +3 -1
@@ -104,6 +104,7 @@ struct xfs_rtgroup;/* Don't propagate sick status to ag health summary during inactivation */ #define XFS_SICK_INO_FORGET (1 << 12)#define XFS_SICK_INO_DIRTREE (1 << 13)/* directory tree structure */ +#define XFS_SICK_INO_FSVERITY (1 << 14)/* fsverity metadata */ /* Primary evidence of health problems in a given group. */ #define XFS_SICK_FS_PRIMARY (XFS_SICK_FS_COUNTERS | \
@@ -140,7 +141,8 @@ struct xfs_rtgroup; XFS_SICK_INO_XATTR | \ XFS_SICK_INO_SYMLINK | \ XFS_SICK_INO_PARENT | \ - XFS_SICK_INO_DIRTREE) + XFS_SICK_INO_DIRTREE | \ + XFS_SICK_INO_FSVERITY)#define XFS_SICK_INO_ZAPPED (XFS_SICK_INO_BMBTD_ZAPPED | \ XFS_SICK_INO_BMBTA_ZAPPED | \
fs/xfs/xfs_fsverity.c +10 -3
@@ -84,16 +84,23 @@ xfs_fsverity_get_descriptor(return error; desc_size =be32_to_cpu (d_desc_size); -if (XFS_IS_CORRUPT (mp, desc_size >FS_VERITY_MAX_DESCRIPTOR_SIZE )) +if (XFS_IS_CORRUPT (mp, desc_size >FS_VERITY_MAX_DESCRIPTOR_SIZE )) { +xfs_inode_mark_sick (XFS_I (inode),XFS_SICK_INO_FSVERITY );return -ERANGE ; -if (XFS_IS_CORRUPT (mp, desc_size > desc_size_pos)) + } + +if (XFS_IS_CORRUPT (mp, desc_size > desc_size_pos)) { +xfs_inode_mark_sick (XFS_I (inode),XFS_SICK_INO_FSVERITY );return -ERANGE ; + }if (!buf_size)return desc_size; -if (XFS_IS_CORRUPT (mp, desc_size > buf_size)) +if (XFS_IS_CORRUPT (mp, desc_size > buf_size)) { +xfs_inode_mark_sick (XFS_I (inode),XFS_SICK_INO_FSVERITY );return -ERANGE ; + } desc_pos =round_down (desc_size_pos - desc_size, blocksize); error =fsverity_pagecache_read (inode, buf, desc_size, desc_pos);
fs/xfs/xfs_health.c +1 -0
@@ -625,6 +625,7 @@ static const struct ioctl_sick_map ino_map[] = { { XFS_SICK_INO_DIR_ZAPPED, XFS_BS_SICK_DIR }, { XFS_SICK_INO_SYMLINK_ZAPPED, XFS_BS_SICK_SYMLINK }, { XFS_SICK_INO_DIRTREE, XFS_BS_SICK_DIRTREE }, + { XFS_SICK_INO_FSVERITY, XFS_BS_SICK_FSVERITY }, };/* Fill out bulkstat health info. */
Signature · 1 line
2.51.2
PATCH v10 22/22 xfs: enable ro-compat fs-verity flag
In reply to Andrey AlbershteynFinalize fs-verity integration in XFS by making kernel fs-verity aware with ro-compat flag.
--- fs/xfs/libxfs/xfs_format.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
fs/xfs/libxfs/xfs_format.h +3 -2
@@ -378,8 +378,9 @@ xfs_sb_has_compat_feature(#define XFS_SB_FEAT_RO_COMPAT_ALL \ (XFS_SB_FEAT_RO_COMPAT_FINOBT | \ XFS_SB_FEAT_RO_COMPAT_RMAPBT | \ - XFS_SB_FEAT_RO_COMPAT_REFLINK| \ - XFS_SB_FEAT_RO_COMPAT_INOBTCNT) + XFS_SB_FEAT_RO_COMPAT_REFLINK | \ + XFS_SB_FEAT_RO_COMPAT_INOBTCNT | \ + XFS_SB_FEAT_RO_COMPAT_VERITY)#define XFS_SB_FEAT_RO_COMPAT_UNKNOWN ~XFS_SB_FEAT_RO_COMPAT_ALLstatic inline bool xfs_sb_has_ro_compat_feature(
Signature · 1 line
2.51.2
Quoted 1 line · Andrey Albershteyn
This series based on v7.1-rc4.
How are we going to merge this? It touches at three subsystem trees (fsverity, vfs/iomap, xfs) so some coordination will be needed.
Quoted 5 lines · Christoph Hellwig
Quoted 1 line · Andrey Albershteyn
This series based on v7.1-rc4.
How are we going to merge this? It touches at three subsystem trees (fsverity, vfs/iomap, xfs) so some coordination will be needed.
As most of the patches are xfs, it's probably make sense to go through xfs tree
Carlos, what do you think?
Signature · 1 line
- Andrey
Carlos Maiolino
maintainerQuoted 11 lines · Andrey Albershteyn
Quoted 5 lines · Christoph Hellwig
Quoted 1 line · Andrey Albershteyn
This series based on v7.1-rc4.
How are we going to merge this? It touches at three subsystem trees (fsverity, vfs/iomap, xfs) so some coordination will be needed.
As most of the patches are xfs, it's probably make sense to go through xfs tree
Carlos, what do you think?
I was expecting this to come through xfs tree too if Eric and Christian agree.
FWIW I'm adding Christian to the Cc
Quoted 5 lines
Signature · 2 lines
-- - Andrey
Carlos Maiolino
maintainerQuoted 8 lines · Carlos Maiolino
Quoted 7 lines · Andrey Albershteyn
Quoted 5 lines · Christoph Hellwig
Quoted 1 line · Andrey Albershteyn
This series based on v7.1-rc4.
How are we going to merge this? It touches at three subsystem trees (fsverity, vfs/iomap, xfs) so some coordination will be needed.
Quoted 8 lines
Quoted 4 lines
As most of the patches are xfs, it's probably make sense to go through xfs tree
Carlos, what do you think?
I was expecting this to come through xfs tree too if Eric and Christian agree.
FWIW I'm adding Christian to the Cc
Woops... Also Adding Amir and Miklos to the Cc list due the overlayfs patch:
Quoted 6 lines
Quoted 6 lines
Signature · 2 lines
-- - Andrey
Eric Biggers
maintainerQuoted 12 lines · Carlos Maiolino
Quoted 11 lines · Carlos Maiolino
Quoted 10 lines · Andrey Albershteyn
Quoted 5 lines · Christoph Hellwig
Quoted 1 line · Andrey Albershteyn
This series based on v7.1-rc4.
How are we going to merge this? It touches at three subsystem trees (fsverity, vfs/iomap, xfs) so some coordination will be needed.
As most of the patches are xfs, it's probably make sense to go through xfs tree
Quoted 8 lines
Quoted 5 lines
Quoted 1 line
Carlos, what do you think?
I was expecting this to come through xfs tree too if Eric and Christian agree.
FWIW I'm adding Christian to the CcWoops... Also Adding Amir and Miklos to the Cc list due the overlayfs patch:
Please go ahead and take it through the XFS tree for 7.2 if you think it's ready.
- Eric
Christian Brauner
maintainerQuoted 8 lines · Carlos Maiolino
Quoted 7 lines · Andrey Albershteyn
Quoted 5 lines · Christoph Hellwig
Quoted 1 line · Andrey Albershteyn
This series based on v7.1-rc4.
How are we going to merge this? It touches at three subsystem trees (fsverity, vfs/iomap, xfs) so some coordination will be needed.
Quoted 7 lines
Quoted 4 lines
As most of the patches are xfs, it's probably make sense to go through xfs tree
Carlos, what do you think?
I was expecting this to come through xfs tree too if Eric and Christian agree.
You may take it through the xfs tree if there are no conflicts with vfs-7.2.iomap. If there are I want to add the iomap changes into vfs-7.2.iomap that you can pull in.
Quoted 6 lines · Christian Brauner
Quoted 2 lines
I was expecting this to come through xfs tree too if Eric and Christian agree.
You may take it through the xfs tree if there are no conflicts with vfs-7.2.iomap. If there are I want to add the iomap changes into vfs-7.2.iomap that you can pull in.
Merging the iomap bits through the iomap branch might make sense, given that iomap usually tends to see quite a bit of activity.
Carlos Maiolino
maintainerQuoted 11 lines · Christoph Hellwig
Quoted 6 lines · Christian Brauner
Quoted 2 lines
I was expecting this to come through xfs tree too if Eric and Christian agree.
You may take it through the xfs tree if there are no conflicts with vfs-7.2.iomap. If there are I want to add the iomap changes into vfs-7.2.iomap that you can pull in.
Merging the iomap bits through the iomap branch might make sense, given that iomap usually tends to see quite a bit of activity.
That sounds good to me. If you want to go ahead and pull in the iomap bits, do so, and give me a heads up when you do it so I'll pull your branch locally.
Cheers.
Christian Brauner
maintainerQuoted 9 lines · Carlos Maiolino
Quoted 8 lines · Christoph Hellwig
Quoted 6 lines · Christian Brauner
Quoted 2 lines
I was expecting this to come through xfs tree too if Eric and Christian agree.
You may take it through the xfs tree if there are no conflicts with vfs-7.2.iomap. If there are I want to add the iomap changes into vfs-7.2.iomap that you can pull in.
Quoted 7 lines
Quoted 3 lines
Merging the iomap bits through the iomap branch might make sense, given that iomap usually tends to see quite a bit of activity.
That sounds good to me. If you want to go ahead and pull in the iomap bits, do so, and give me a heads up when you do it so I'll pull your branch locally.
Great, can the series please be resent based on current vfs-7.2.iomap then please? Because the iomap changes in this series don't apply cleanly on vfs-7.2.iomap so we already have merge conflicts...
Quoted 14 lines · Christian Brauner
Quoted 13 lines · Carlos Maiolino
Quoted 11 lines · Christoph Hellwig
Quoted 6 lines · Christian Brauner
Quoted 2 lines
I was expecting this to come through xfs tree too if Eric and Christian agree.
You may take it through the xfs tree if there are no conflicts with vfs-7.2.iomap. If there are I want to add the iomap changes into vfs-7.2.iomap that you can pull in.
Merging the iomap bits through the iomap branch might make sense, given that iomap usually tends to see quite a bit of activity.
Quoted 8 lines
Quoted 3 lines
That sounds good to me. If you want to go ahead and pull in the iomap bits, do so, and give me a heads up when you do it so I'll pull your branch locally.
Great, can the series please be resent based on current vfs-7.2.iomap then please? Because the iomap changes in this series don't apply cleanly on vfs-7.2.iomap so we already have merge conflicts...
Sure, I will resend soon.
Signature · 1 line
- Andrey
Quoted 14 lines · Christian Brauner
Quoted 13 lines · Carlos Maiolino
Quoted 11 lines · Christoph Hellwig
Quoted 6 lines · Christian Brauner
Quoted 2 lines
I was expecting this to come through xfs tree too if Eric and Christian agree.
You may take it through the xfs tree if there are no conflicts with vfs-7.2.iomap. If there are I want to add the iomap changes into vfs-7.2.iomap that you can pull in.
Merging the iomap bits through the iomap branch might make sense, given that iomap usually tends to see quite a bit of activity.
Quoted 8 lines
Quoted 3 lines
That sounds good to me. If you want to go ahead and pull in the iomap bits, do so, and give me a heads up when you do it so I'll pull your branch locally.
Great, can the series please be resent based on current vfs-7.2.iomap then please? Because the iomap changes in this series don't apply cleanly on vfs-7.2.iomap so we already have merge conflicts...
hmm do you mean this branch?
https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git/log/?h=vfs-7.2.iomap
patches 07..09 seems to apply cleanly. The only conflict I see is in the overlayfs patch 03. This is because [1] (is in -rc5) is missing in vfs-7.2.iomap.
Signature · 1 line
- Andrey
Quoted 24 lines · Andrey Albershteyn
Quoted 14 lines · Christian Brauner
Quoted 13 lines · Carlos Maiolino
Quoted 11 lines · Christoph Hellwig
Quoted 6 lines · Christian Brauner
Quoted 2 lines
I was expecting this to come through xfs tree too if Eric and Christian agree.
You may take it through the xfs tree if there are no conflicts with vfs-7.2.iomap. If there are I want to add the iomap changes into vfs-7.2.iomap that you can pull in.
Merging the iomap bits through the iomap branch might make sense, given that iomap usually tends to see quite a bit of activity.
Quoted 8 lines
Quoted 3 lines
That sounds good to me. If you want to go ahead and pull in the iomap bits, do so, and give me a heads up when you do it so I'll pull your branch locally.
Great, can the series please be resent based on current vfs-7.2.iomap then please? Because the iomap changes in this series don't apply cleanly on vfs-7.2.iomap so we already have merge conflicts...
Quoted 8 lines
hmm do you mean this branch?
https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git/log/?h=vfs-7.2.iomappatches 07..09 seems to apply cleanly. The only conflict I see is in the overlayfs patch 03. This is because [1] (is in -rc5) is missing in vfs-7.2.iomap.
Christian, ping
Would be nice to have iomap in vfs, so Carlos can pull and test the rest
Signature · 1 line
- Andrey
Christian Brauner
maintainerQuoted 32 lines · Andrey Albershteyn
Quoted 31 lines · Andrey Albershteyn
Quoted 14 lines · Christian Brauner
Quoted 13 lines · Carlos Maiolino
Quoted 11 lines · Christoph Hellwig
Quoted 6 lines · Christian Brauner
Quoted 2 lines
I was expecting this to come through xfs tree too if Eric and Christian agree.
You may take it through the xfs tree if there are no conflicts with vfs-7.2.iomap. If there are I want to add the iomap changes into vfs-7.2.iomap that you can pull in.
Merging the iomap bits through the iomap branch might make sense, given that iomap usually tends to see quite a bit of activity.
Quoted 8 lines
Quoted 3 lines
That sounds good to me. If you want to go ahead and pull in the iomap bits, do so, and give me a heads up when you do it so I'll pull your branch locally.
Great, can the series please be resent based on current vfs-7.2.iomap then please? Because the iomap changes in this series don't apply cleanly on vfs-7.2.iomap so we already have merge conflicts...
hmm do you mean this branch?
https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git/log/?h=vfs-7.2.iomappatches 07..09 seems to apply cleanly. The only conflict I see is in the overlayfs patch 03. This is because [1] (is in -rc5) is missing in vfs-7.2.iomap.
Quoted 6 lines
Quoted 1 line
Christian, ping
Would be nice to have iomap in vfs, so Carlos can pull and test the rest
Applied but note IOMAP_F_FSVERITY
changed from (1U << 10) to (1U << 11) since we have another flag addition this cycle.
Quoted 35 lines · Christian Brauner
Quoted 34 lines · Andrey Albershteyn
Quoted 32 lines · Andrey Albershteyn
Quoted 14 lines · Christian Brauner
Quoted 13 lines · Carlos Maiolino
Quoted 11 lines · Christoph Hellwig
Quoted 6 lines · Christian Brauner
Quoted 2 lines
I was expecting this to come through xfs tree too if Eric and Christian agree.
You may take it through the xfs tree if there are no conflicts with vfs-7.2.iomap. If there are I want to add the iomap changes into vfs-7.2.iomap that you can pull in.
Merging the iomap bits through the iomap branch might make sense, given that iomap usually tends to see quite a bit of activity.
Quoted 8 lines
Quoted 3 lines
That sounds good to me. If you want to go ahead and pull in the iomap bits, do so, and give me a heads up when you do it so I'll pull your branch locally.
Great, can the series please be resent based on current vfs-7.2.iomap then please? Because the iomap changes in this series don't apply cleanly on vfs-7.2.iomap so we already have merge conflicts...
hmm do you mean this branch?
https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git/log/?h=vfs-7.2.iomappatches 07..09 seems to apply cleanly. The only conflict I see is in the overlayfs patch 03. This is because [1] (is in -rc5) is missing in vfs-7.2.iomap.
Quoted 8 lines
Quoted 4 lines
Christian, ping
Would be nice to have iomap in vfs, so Carlos can pull and test the rest
Applied but note
IOMAP_F_FSVERITY
changed from (1U << 10) to (1U << 11) since we have another flag addition this cycle.
Oh I haven't noticed that, thanks!
Signature · 1 line
- Andrey
Carlos Maiolino
maintainerQuoted 38 lines · Andrey Albershteyn
Quoted 37 lines · Christian Brauner
Quoted 36 lines · Andrey Albershteyn
Quoted 24 lines · Andrey Albershteyn
Quoted 14 lines · Christian Brauner
Quoted 13 lines · Carlos Maiolino
Quoted 11 lines · Christoph Hellwig
Quoted 6 lines · Christian Brauner
Quoted 2 lines
I was expecting this to come through xfs tree too if Eric and Christian agree.
You may take it through the xfs tree if there are no conflicts with vfs-7.2.iomap. If there are I want to add the iomap changes into vfs-7.2.iomap that you can pull in.
Merging the iomap bits through the iomap branch might make sense, given that iomap usually tends to see quite a bit of activity.
Quoted 8 lines
Quoted 3 lines
That sounds good to me. If you want to go ahead and pull in the iomap bits, do so, and give me a heads up when you do it so I'll pull your branch locally.
Great, can the series please be resent based on current vfs-7.2.iomap then please? Because the iomap changes in this series don't apply cleanly on vfs-7.2.iomap so we already have merge conflicts...
Quoted 8 lines
hmm do you mean this branch?
https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git/log/?h=vfs-7.2.iomappatches 07..09 seems to apply cleanly. The only conflict I see is in the overlayfs patch 03. This is because [1] (is in -rc5) is missing in vfs-7.2.iomap.
Christian, ping
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
Would be nice to have iomap in vfs, so Carlos can pull and test the rest
Applied but note
IOMAP_F_FSVERITY
changed from (1U << 10) to (1U << 11) since we have another flag addition this cycle.Oh I haven't noticed that, thanks!
Thanks Christian. I'll deal with the rest of the series next week!
Quoted 4 lines
Signature · 2 lines
-- - Andrey
This series was applied to jaegeuk/f2fs.git (dev) by Christian Brauner <[email protected]>:
Hello:
This series was applied to jaegeuk/f2fs.git (dev)
by Christian Brauner <[email protected]>:
Quoted 9 lines · On Wed, 20 May 2026 14:36:58 +0200 you wrote:
Hi all,
This patch series adds fs-verity support for XFS. This version stores merkle tree beyond end of the file, the same way as ext4 does it. The difference is that verity descriptor is stored at the next aligned 64k block after the merkle tree last block. This is done due to sparse merkle tree which doesn't store hashes of zero data blocks.
[...]
Here is the summary with links:
- [f2fs-dev,v10,01/22] fsverity: report validation errors through fserror to fsnotify (no matching commit)
- [f2fs-dev,v10,02/22] fsverity: expose ensure_fsverity_info()
(no matching commit)
- [f2fs-dev,v10,03/22] ovl: use core fsverity ensure info interface
(no matching commit)
- [f2fs-dev,v10,04/22] fsverity: generate and store zero-block hash
https://git.kernel.org/jaegeuk/f2fs/c/07d09774e2bf - [f2fs-dev,v10,05/22] fsverity: pass digest size and hash of the all-zeroes block to ->write (no matching commit) - [f2fs-dev,v10,06/22] fsverity: hoist pagecache_read from f2fs/ext4 to fsverity (no matching commit) - [f2fs-dev,v10,07/22] iomap: introduce IOMAP_F_FSVERITY and teach writeback to handle fsverity https://git.kernel.org/jaegeuk/f2fs/c/63e242afa466 - [f2fs-dev,v10,08/22] iomap: teach iomap to read files with fsverity https://git.kernel.org/jaegeuk/f2fs/c/1d140731753a - [f2fs-dev,v10,09/22] iomap: introduce iomap_fsverity_write() for writing fsverity metadata https://git.kernel.org/jaegeuk/f2fs/c/36a36c4cac91
- [f2fs-dev,v10,10/22] xfs: introduce fsverity on-disk changes
(no matching commit)
- [f2fs-dev,v10,11/22] xfs: initialize fs-verity on file open
(no matching commit)
- [f2fs-dev,v10,12/22] xfs: don't allow to enable DAX on fs-verity sealed inode (no matching commit)
- [f2fs-dev,v10,13/22] xfs: disable direct read path for fs-verity files
(no matching commit)
- [f2fs-dev,v10,14/22] xfs: handle fsverity I/O in write/read path
(no matching commit)
- [f2fs-dev,v10,15/22] xfs: use read ioend for fsverity data verification
(no matching commit)
- [f2fs-dev,v10,16/22] xfs: add fs-verity support
(no matching commit)
- [f2fs-dev,v10,17/22] xfs: remove unwritten extents after preallocations in fsverity metadata (no matching commit)
- [f2fs-dev,v10,18/22] xfs: add fs-verity ioctls
(no matching commit)
- [f2fs-dev,v10,19/22] xfs: advertise fs-verity being available on filesystem (no matching commit)
- [f2fs-dev,v10,20/22] xfs: check and repair the verity inode flag state
(no matching commit)
- [f2fs-dev,v10,21/22] xfs: introduce health state for corrupted fsverity metadata (no matching commit)
- [f2fs-dev,v10,22/22] xfs: enable ro-compat fs-verity flag
(no matching commit)
You are awesome, thank you!
Signature · 2 lines
Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html