From: Andrey Albershteyn <aalbersh@kernel.org>
To: djwong@kernel.org, ebiggers@kernel.org, hch@lst.de,
Carlos Maiolino <cem@kernel.org>
Cc: Andrey Albershteyn <aalbersh@kernel.org>,
fsverity@lists.linux.dev, linux-fsdevel@vger.kernel.org,
linux-xfs@vger.kernel.org, linux-unionfs@vger.kernel.org,
linux-ext4@vger.kernel.org,
linux-f2fs-devel@lists.sourceforge.net,
linux-btrfs@vger.kernel.org, david@fromorbit.com
Subject: [PATCH v17 00/21] fs-verity support for XFS with post EOF merkle tree
Date: Sat, 3 Oct 2026 00:36:41 +0200 [thread overview]
Message-ID: <20261002223705.2175542-1-aalbersh@kernel.org> (raw)
Hi all,
This is next revision of fsverity for XFS.
Patches without review:
[PATCH v17 12/21] xfs: use read ioend for fsverity data verification
This series based on block/for-next (has lazy-bounce series)
block/for-next:
https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux.git/log/?h=for-next
kernel:
https://git.kernel.org/pub/scm/linux/kernel/git/aalbersh/xfs-linux.git/log/?h=fsverity
xfsprogs:
https://git.kernel.org/pub/scm/linux/kernel/git/aalbersh/xfsprogs-dev.git/log/?h=fsverity
xfstests:
https://git.kernel.org/pub/scm/linux/kernel/git/aalbersh/xfstests-dev.git/log/?h=fsverity
v16:
https://lore.kernel.org/fsverity/arJC542mXklAeswE@aalbersh-thinkpadx1carbongen13.rmtcz.csb/T/#t
v15:
https://lore.kernel.org/fsverity/20260817070240.GA17371@lst.de/T/#t
v14:
https://lore.kernel.org/fsverity/anmFWhPNOqe4uyht@aalbersh-thinkpadx1carbongen13.rmtcz.csb/T/#t
v13:
https://lore.kernel.org/fsverity/20260721184346.416657-1-aalbersh@kernel.org/T/#t
v12:
https://lore.kernel.org/fsverity/al8xgOwueDOzGakK@aalbersh-thinkpadx1carbongen13.rmtcz.csb/T/#t
v11:
https://lore.kernel.org/all/20260710085256.3464201-1-aalbersh@kernel.org/
v10:
https://lore.kernel.org/fsverity/20260520123722.405752-1-aalbersh@kernel.org/#r
v9:
https://lore.kernel.org/fsverity/20260428083332.768693-1-aalbersh@kernel.org/#r
To: djwong@kernel.org
To: ebiggers@kernel.org
To: hch@lst.de
To: Carlos Maiolino <cem@kernel.org>
Cc: fsverity@lists.linux.dev
Cc: linux-fsdevel@vger.kernel.org
Cc: linux-xfs@vger.kernel.org
Cc: linux-unionfs@vger.kernel.org
Cc: linux-ext4@vger.kernel.org
Cc: linux-f2fs-devel@lists.sourceforge.net
Cc: linux-btrfs@vger.kernel.org
Cc: david@fromorbit.com
---
Changes in v17:
- Add mempool for fsverity ioends cache
- Add xfs_fsverity_reset_inode() as a common clean up function
- Changed ILOCK_SHARED to ILOCK_EXCL for xfs_bmap_last_extent()
- Swap order of truncate_inode_pages() and ilock() due to ABBA
- Add xfs_fsverity_is_hashes_of_zeroed_blocks() helper
- Removed EINVAL and EFBIG from scrub as ambiguous
Changes in v16:
- Rebase to block/for-next
- Removed work_struct from ioend in favor of kmem_cache structs
- Minor adjustments from v15 review
- Skip written extents in lower level of __xfs_bunmapi()
Changes in v15:
- Pull BIO in task context patches
- Drop flag argument in xfs_free_eofblocks()
- Call xfs_free_eofblocks() on fsverity inodes
- Comments and commit messages updates
- Rebased to v7.2-rc7
- Dropped patch for fsverity_fill_zerohash() with highmem optimization
Changes in v14:
- Rebase to lazy-bounce@hch-misc
- Adjust read ioends to BIO in task context flow
- MMAPLOCK/sb_internal deadlock fix reported by sashiko
- Add missing delalloc clean up in verity_end_enable
- Use xfs_free_eofblocks() instead of writing own clean up routine
- Modify xfs_free_eofblocks() to be able to clean unwritten only
- Dropped fix patch for truncate/set_size check
- Various minor code and #include rearrangements for bisecting
Changes in v13:
- Hoisted statx reporting to common code
- Added read ioend sorted for worker self-deadlock fix
- Adjusted fsverity flags in zoned write path
Changes in v12:
- Refactored xfs_fsverity_cancel_unwritten()
- Switched to using inode_set_flags()
- Add a lock for COW fork reading
- Add pagecache truncation in cleanup path
- Added ERANGE and EBADMSG to fsverity scrub handling
- Add missing XFS_FSVERITY_CONSTRUCTION in various xfs_iomap
- Rebase to -rc3
Changes in v11:
- Drop wrong overlayfs patch
- Drop already merged iomap and fsverity patches
- Update to I_INO() use instead of ip->i_ino
- Sashiko.dev fixes. See list of issues below.
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/20260217231937.1183679-1-aalbersh@kernel.org/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/20250728-fsverity-v1-0-9e5443af0e34@kernel.org
Andrey Albershteyn (19):
fsverity: report validation errors through fserror to fsnotify
fsverity: expose ensure_fsverity_info()
fsverity: pass digest size and hash of the all-zeroes block to ->write
fsverity: hoist pagecache_read from f2fs/ext4 to fsverity
fsverity: don't allow setting DAX file attribute on fsverity files
fsverity: hoist statx reporting of fs-verity flag
xfs: introduce fsverity on-disk changes
xfs: don't allow to enable DAX on fs-verity sealed inode
xfs: disable direct read path for fs-verity files
xfs: don't report dio_mem_align and dio_offset_align for fsverity
files
xfs: handle fsverity I/O in write/read path
xfs: use read ioend for fsverity data verification
xfs: add XFS_BMAPI_UNWRITTEN to unmap unwritten extents in
__xfs_bunmapi()
xfs: don't remove written extents past EOF on fsverity inodes
xfs: add fs-verity support
xfs: initialize fs-verity on file open
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/inode.c | 3 -
fs/btrfs/verity.c | 6 +-
fs/ext4/inode.c | 5 +-
fs/ext4/verity.c | 36 +--
fs/f2fs/file.c | 5 +-
fs/f2fs/verity.c | 34 +--
fs/file_attr.c | 11 +-
fs/stat.c | 6 +-
fs/verity/enable.c | 4 +-
fs/verity/open.c | 26 +-
fs/verity/pagecache.c | 33 +++
fs/verity/verify.c | 4 +
fs/xfs/Makefile | 1 +
fs/xfs/libxfs/xfs_bmap.c | 15 +-
fs/xfs/libxfs/xfs_bmap.h | 6 +-
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 | 5 +-
fs/xfs/libxfs/xfs_sb.c | 4 +
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 | 49 +++-
fs/xfs/xfs_bmap_util.c | 31 ++-
fs/xfs/xfs_file.c | 71 +++--
fs/xfs/xfs_fsverity.c | 489 +++++++++++++++++++++++++++++++++
fs/xfs/xfs_fsverity.h | 47 ++++
fs/xfs/xfs_health.c | 1 +
fs/xfs/xfs_inode.h | 6 +
fs/xfs/xfs_ioctl.c | 14 +
fs/xfs/xfs_ioend.c | 53 +++-
fs/xfs/xfs_ioend.h | 4 +-
fs/xfs/xfs_iomap.c | 37 ++-
fs/xfs/xfs_iomap.h | 5 +-
fs/xfs/xfs_iops.c | 12 +-
fs/xfs/xfs_message.c | 4 +
fs/xfs/xfs_message.h | 1 +
fs/xfs/xfs_mount.h | 4 +
fs/xfs/xfs_super.c | 31 ++-
include/linux/fsverity.h | 10 +-
43 files changed, 1079 insertions(+), 141 deletions(-)
create mode 100644 fs/xfs/xfs_fsverity.c
create mode 100644 fs/xfs/xfs_fsverity.h
Range-diff against v16:
-: ------------ > 1: c14aea60fb61 fsverity: report validation errors through fserror to fsnotify
1: d234049f2fc6 ! 2: ba2ec9993a12 fsverity: expose ensure_fsverity_info()
@@ Commit message
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Acked-by: Eric Biggers <ebiggers@kernel.org>
- Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
+ Reviewed-by: Christoph Hellwig <hch@lst.de>
## fs/verity/open.c ##
@@ fs/verity/open.c: int fsverity_get_descriptor(struct inode *inode,
2: ce8681774085 ! 3: 68694ea8ba0d fsverity: pass digest size and hash of the all-zeroes block to ->write
@@ Commit message
hashes of zeroed data blocks. XFS will use this to decide if it want to
store tree block full of these hashes.
+ Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
Acked-by: Eric Biggers <ebiggers@kernel.org>
Acked-by: David Sterba <dsterba@suse.com>
- Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
## fs/btrfs/verity.c ##
@@ fs/btrfs/verity.c: static struct page *btrfs_read_merkle_tree_page(struct inode *inode,
3: 363bb4311e70 = 4: 5732f007e676 fsverity: hoist pagecache_read from f2fs/ext4 to fsverity
4: 159c890b697c ! 5: 9928ceefe211 fsverity: don't allow setting DAX file attribute on fsverity files
@@ Commit message
Note, that the only other filesystem supporting DAX and fsverity is
ext4, and ext4 does check for this case.
+ Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Eric Biggers <ebiggers@kernel.org>
- Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
## fs/file_attr.c ##
@@ fs/file_attr.c: static int fileattr_set_prepare(struct inode *inode,
5: 4989457dc89c ! 6: 8f866da8730c fsverity: hoist statx reporting of fs-verity flag
@@ Commit message
Fixes: 146054090b08 ("btrfs: initial fsverity support")
Cc: stable@vger.kernel.org
+ Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
Acked-by: Eric Biggers <ebiggers@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
- Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
## fs/btrfs/inode.c ##
@@ fs/btrfs/inode.c: static int btrfs_getattr(struct mnt_idmap *idmap,
6: 95e50d365df7 = 7: d93e466c36fd xfs: introduce fsverity on-disk changes
7: bf0fbecea27a = 8: 4bcf1275fa38 xfs: don't allow to enable DAX on fs-verity sealed inode
8: ac7fa296202d ! 9: 082d5f39ae5a xfs: disable direct read path for fs-verity files
@@ Commit message
through the DIO path.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
- Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
+ Reviewed-by: Christoph Hellwig <hch@lst.de>
## fs/xfs/xfs_file.c ##
@@
9: 67aeb55c4031 ! 10: 21b92f51fd5e xfs: don't report dio_mem_align and dio_offset_align for fsverity files
@@ Commit message
to the buffered IO is used in this case. The zero alignment values also
mean that DIO is not supported on this file, see statx(2).
+ Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
Acked-by: Eric Biggers <ebiggers@kernel.org>
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
- Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
## fs/xfs/xfs_iops.c ##
@@
10: 4dae04bdd7f3 ! 11: 929a7172c341 xfs: handle fsverity I/O in write/read path
@@ Commit message
Introduce a new inode flag meaning that merkle tree is being build on
the inode.
+ Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
- Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
## fs/xfs/Makefile ##
@@ fs/xfs/Makefile: xfs-$(CONFIG_XFS_POSIX_ACL) += xfs_acl.o
@@ fs/xfs/libxfs/xfs_bmap.c: xfs_bmapi_convert_one_delalloc(
*/
if (!isnullstartblock(bma.got.br_startblock)) {
+ if (xfs_iflags_test(ip, XFS_VERITY_CONSTRUCTION) &&
-+ XFS_FSB_TO_B(mp, bma.got.br_startoff) >=
-+ xfs_fsverity_metadata_offset(ip))
++ offset >= xfs_fsverity_metadata_offset(ip))
+ flags |= IOMAP_F_FSVERITY;
xfs_bmbt_to_iomap(ip, iomap, &bma.got, 0, flags,
xfs_iomap_inode_sequence(ip, flags));
@@ fs/xfs/libxfs/xfs_bmap.c: xfs_bmapi_convert_one_delalloc(
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))
++ offset >= xfs_fsverity_metadata_offset(ip))
+ flags |= IOMAP_F_FSVERITY;
+
ASSERT(!isnullstartblock(bma.got.br_startblock));
@@ fs/xfs/xfs_iomap.c: xfs_direct_write_iomap_begin(
/*
* COW writes may allocate delalloc space or convert unwritten COW
* extents, so we need to make sure to take the lock exclusively here.
+@@ fs/xfs/xfs_iomap.c: xfs_direct_write_iomap_begin(
+ trace_xfs_iomap_found(ip, offset, length - offset, XFS_COW_FORK, &cmap);
+ if (imap.br_startblock != HOLESTARTBLOCK) {
+ seq = xfs_iomap_inode_sequence(ip, 0);
+- error = xfs_bmbt_to_iomap(ip, srcmap, &imap, flags, 0, seq);
++ error = xfs_bmbt_to_iomap(ip, srcmap, &imap, flags,
++ iomap_flags & IOMAP_F_FSVERITY, seq);
+ if (error)
+ goto out_unlock;
+ }
@@ fs/xfs/xfs_iomap.c: xfs_zoned_direct_write_iomap_begin(
return error;
}
@@ fs/xfs/xfs_iomap.c: xfs_buffered_write_iomap_begin(
/* we can't use delayed allocations when using extent size hints */
if (xfs_get_extsz_hint(ip))
+@@ fs/xfs/xfs_iomap.c: xfs_buffered_write_iomap_begin(
+
+ found_cow:
+ if (imap.br_startoff <= offset_fsb) {
+- error = xfs_bmbt_to_iomap(ip, srcmap, &imap, flags, 0,
++ error = xfs_bmbt_to_iomap(ip, srcmap, &imap, flags,
++ iomap_flags & IOMAP_F_FSVERITY,
+ xfs_iomap_inode_sequence(ip, 0));
+ if (error)
+ goto out_unlock;
@@ fs/xfs/xfs_iomap.c: xfs_read_iomap_begin(
bool shared = false;
unsigned int lockmode = XFS_ILOCK_SHARED;
11: 79f81266cd22 ! 12: db144b392a91 xfs: use read ioend for fsverity data verification
@@ Commit message
Add a simple helper to check that this is not fsverity metadata but file
data that needs verification.
- Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
## fs/xfs/xfs_aops.c ##
@@ fs/xfs/xfs_fsverity.c
#include <linux/iomap.h>
+struct kmem_cache *xfs_fsverity_ioend_cache;
++mempool_t xfs_fsverity_ioend_pool;
++
++#define XFS_FSVERITY_IOEND_POOL_MIN 128
++
++/*
++ * Back the fsverity ioend allocations with a mempool so that read I/O
++ * completion always makes forward progress and cannot deadlock
++ */
++int
++xfs_fsverity_init(void)
++{
++ return mempool_init_slab_pool(&xfs_fsverity_ioend_pool,
++ XFS_FSVERITY_IOEND_POOL_MIN, xfs_fsverity_ioend_cache);
++}
++
++void
++xfs_fsverity_exit(void)
++{
++ mempool_exit(&xfs_fsverity_ioend_pool);
++}
+
loff_t
xfs_fsverity_metadata_offset(
@@ fs/xfs/xfs_fsverity.h
#include "xfs_platform.h"
+#include <linux/iomap.h>
++#include <linux/mempool.h>
#ifdef CONFIG_FS_VERITY
++int xfs_fsverity_init(void);
++void xfs_fsverity_exit(void);
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 int xfs_fsverity_init(void)
++{
++ return 0;
++}
++static inline void xfs_fsverity_exit(void)
++{
++}
static inline loff_t xfs_fsverity_metadata_offset(const struct xfs_inode *ip)
{
WARN_ON_ONCE(1);
@@ fs/xfs/xfs_fsverity.h
+};
+
+extern struct kmem_cache *xfs_fsverity_ioend_cache;
++extern mempool_t xfs_fsverity_ioend_pool;
+
#endif /* __XFS_FSVERITY_H__ */
@@ fs/xfs/xfs_ioend.c
+ struct iomap_ioend *ioend = fsv_ioend->ioend;
+ struct bio *bio = &ioend->io_bio;
+
-+ kmem_cache_free(xfs_fsverity_ioend_cache, fsv_ioend);
++ mempool_free(fsv_ioend, &xfs_fsverity_ioend_pool);
+
+ if (!bio->bi_status)
+ fsverity_verify_bio(ioend->io_vi, bio);
@@ fs/xfs/xfs_ioend.c: xfs_end_io_read(
}
+ /*
-+ * If we have fsverity and block device integrity attached to this bio,
-+ * we need to run fsverity verification of data folios from a separate
-+ * fsverity workqueue. This is necessary to avoid deadlocking due to
-+ * fsverity issuing more reads of fsverity metadata which would be
-+ * processed by the same worker in the BIO completion workqueue.
-+ *
-+ * Without block device integrity, fsverity metadata IO will not use
-+ * ioends for completion.
++ * If we have fsverity on this bio, we need to run fsverity verification
++ * of data folios from a separate fsverity workqueue. This is necessary
++ * to avoid deadlocking due to fsverity issuing more reads of fsverity
++ * metadata which would be processed by the same worker in the BIO
++ * completion workqueue.
+ */
+ if (IS_ENABLED(CONFIG_FS_VERITY) && !error && ioend->io_vi &&
+ xfs_fsverity_is_file_data(ip, ioend->io_offset)) {
-+ if (ioend->io_flags & IOMAP_IOEND_INTEGRITY) {
-+ fsv_ioend = kmem_cache_zalloc(xfs_fsverity_ioend_cache,
-+ GFP_KERNEL);
-+ if (!fsv_ioend) {
-+ iomap_finish_ioends(ioend, -ENOMEM);
-+ return;
-+ }
-+ fsv_ioend->ioend = ioend;
-+ INIT_WORK(&fsv_ioend->work, xfs_end_fsverity_io_read);
++ fsv_ioend = mempool_alloc(&xfs_fsverity_ioend_pool,
++ GFP_NOFS);
++ fsv_ioend->ioend = ioend;
++ INIT_WORK(&fsv_ioend->work, xfs_end_fsverity_io_read);
+
-+ fsverity_enqueue_verify_work(&fsv_ioend->work);
-+ return;
-+ }
-+
-+ fsverity_verify_bio(ioend->io_vi, &ioend->io_bio);
-+ error = blk_status_to_errno(ioend->io_bio.bi_status);
++ fsverity_enqueue_verify_work(&fsv_ioend->work);
++ return;
+ }
+
iomap_finish_ioends(ioend, error);
@@ fs/xfs/xfs_super.c: xfs_init_caches(void)
+ sizeof(struct xfs_fsverity_ioend),
+ 0, 0, NULL);
+ if (!xfs_fsverity_ioend_cache)
-+ goto out_destroy_fsverity_ioend_cache;
++ goto out_destroy_parent_args_cache;
+#endif
+
return 0;
+#ifdef CONFIG_FS_VERITY
-+ out_destroy_fsverity_ioend_cache:
-+ kmem_cache_destroy(xfs_fsverity_ioend_cache);
++ out_destroy_parent_args_cache:
++ kmem_cache_destroy(xfs_parent_args_cache);
+#endif
out_destroy_xmi_cache:
kmem_cache_destroy(xfs_xmi_cache);
@@ fs/xfs/xfs_super.c: xfs_destroy_caches(void)
kmem_cache_destroy(xfs_parent_args_cache);
kmem_cache_destroy(xfs_xmd_cache);
kmem_cache_destroy(xfs_xmi_cache);
+@@ fs/xfs/xfs_super.c: init_xfs_fs(void)
+ if (error)
+ goto out;
+
+- error = xfs_init_workqueues();
++ error = xfs_fsverity_init();
+ if (error)
+ goto out_destroy_caches;
+
++ error = xfs_init_workqueues();
++ if (error)
++ goto out_fsverity_exit;
++
+ error = xfs_mru_cache_init();
+ if (error)
+ goto out_destroy_wq;
+@@ fs/xfs/xfs_super.c: init_xfs_fs(void)
+ xfs_mru_cache_uninit();
+ out_destroy_wq:
+ xfs_destroy_workqueues();
++ out_fsverity_exit:
++ xfs_fsverity_exit();
+ out_destroy_caches:
+ xfs_destroy_caches();
+ out:
+@@ fs/xfs/xfs_super.c: exit_xfs_fs(void)
+ xfs_cleanup_procfs();
+ xfs_mru_cache_uninit();
+ xfs_destroy_workqueues();
++ xfs_fsverity_exit();
+ xfs_destroy_caches();
+ xfs_uuid_table_free();
+ }
12: 7b7e33fef0ab ! 13: 5f00c1287b5e xfs: add XFS_BMAPI_UNWRITTEN to unmap unwritten extents in __xfs_bunmapi()
@@ Commit message
written ones in place. This will be used in following patch to clean up
unwritten extents on fsverity inodes.
- Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
+ Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
## fs/xfs/libxfs/xfs_bmap.c ##
@@ fs/xfs/libxfs/xfs_bmap.c: __xfs_bunmapi(
@@ fs/xfs/libxfs/xfs_bmap.c: __xfs_bunmapi(
del.br_blockcount = end + 1 - del.br_startoff;
+ if ((flags & XFS_BMAPI_UNWRITTEN) &&
-+ del.br_state != XFS_EXT_UNWRITTEN)
++ del.br_state != XFS_EXT_UNWRITTEN)
+ goto skip;
+
if (!isrt || (flags & XFS_BMAPI_REMAP))
13: 44817f70a46b ! 14: 9a82d542d940 xfs: don't remove written extents past EOF on fsverity inodes
@@ Commit message
undergoing merkle tree construction need to be skipped in case reclaim
takes place.
- Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
+ Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
## fs/xfs/xfs_bmap_util.c ##
@@
@@ fs/xfs/xfs_bmap_util.c: xfs_can_free_eofblocks(
return false;
+ /*
-+ * Don't clean fsverity inodes which have merkle tree being built, the
++ * Don't clean fsverity inodes as they already have been cleaned up and
++ * are read-only. Skip inodes which have merkle tree being built, the
+ * merkle tree is written beyond EOF
+ */
-+ if (xfs_iflags_test(ip, XFS_VERITY_CONSTRUCTION))
++ if (fsverity_active(VFS_IC(ip)) ||
++ xfs_iflags_test(ip, XFS_VERITY_CONSTRUCTION))
+ return false;
+
/*
@@ fs/xfs/xfs_bmap_util.c: xfs_free_eofblocks(
xfs_ilock(ip, XFS_ILOCK_EXCL);
xfs_trans_ijoin(tp, ip, 0);
++ /*
++ * While fs-verity writes metadata after EOF, it can leave unwritten
++ * preallocations. Clear all that out.
++ */
+ if (has_verity)
+ bmapi_flags |= XFS_BMAPI_UNWRITTEN;
+
14: 6c1468facf03 ! 15: 420fb1a97664 xfs: add fs-verity support
@@ Commit message
Pro-actively remove any unwritten extents as we use last extent to
locate descriptor.
- Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
+ Reviewed-by: Christoph Hellwig <hch@lst.de>
## fs/xfs/xfs_fsverity.c ##
@@
@@ fs/xfs/xfs_fsverity.c
+#include <linux/pagemap.h>
struct kmem_cache *xfs_fsverity_ioend_cache;
-
+ mempool_t xfs_fsverity_ioend_pool;
@@ fs/xfs/xfs_fsverity.c: xfs_fsverity_is_file_data(
return fsverity_active(VFS_IC(ip)) &&
offset < xfs_fsverity_metadata_offset(ip);
@@ fs/xfs/xfs_fsverity.c: xfs_fsverity_is_file_data(
+ uint32_t blocksize = i_blocksize(VFS_I(ip));
+ xfs_fileoff_t last_block_offset;
+
-+ ASSERT(inode->i_flags & S_VERITY);
-+ xfs_ilock(ip, XFS_ILOCK_SHARED);
++ xfs_ilock(ip, XFS_ILOCK_EXCL);
++ /*
++ * Serialize reading of inode->i_flags with xfs_scrub clearing of this
++ * flag if inode is corrupted.
++ */
++ if (!(inode->i_flags & S_VERITY)) {
++ xfs_iunlock(ip, XFS_ILOCK_EXCL);
++ return -ENODATA;
++ }
+ error = xfs_bmap_last_extent(NULL, ip, XFS_DATA_FORK, &rec, &is_empty);
-+ xfs_iunlock(ip, XFS_ILOCK_SHARED);
++ xfs_iunlock(ip, XFS_ILOCK_EXCL);
+ if (error)
+ return error;
+
@@ fs/xfs/xfs_fsverity.c: xfs_fsverity_is_file_data(
+ return error;
+ }
+
-+ xfs_ilock(ip, XFS_ILOCK_EXCL);
-+ xfs_trans_ijoin(tp, ip, 0);
-+
+ truncate_inode_pages(VFS_I(ip)->i_mapping, XFS_ISIZE(ip));
+
++ xfs_ilock(ip, XFS_ILOCK_EXCL);
++ xfs_trans_ijoin(tp, ip, 0);
++
+ /*
+ * We remove post EOF data, no need to update i_size as fsverity
+ * didn't move i_size in the first place
@@ fs/xfs/xfs_fsverity.c: xfs_fsverity_is_file_data(
+ return error;
+}
+
++static int
++xfs_fsverity_reset_inode(
++ struct xfs_inode *ip)
++{
++ int error;
++ struct xfs_mount *mp = ip->i_mount;
++ struct xfs_trans *tp;
++
++ error = xfs_fsverity_delete_metadata(ip);
++ if (error)
++ return error;
++
++ /*
++ * First, let's clean in-memory fsverity flag and then reset it on the
++ * disk
++ */
++ inode_set_flags(VFS_I(ip), 0, S_VERITY);
++
++ /*
++ * Set fsverity inode flag
++ */
++ error = xfs_trans_alloc_inode(ip, &M_RES(mp)->tr_ichange,
++ 0, 0, false, &tp);
++ if (error)
++ return error;
++
++ ip->i_diflags2 &= ~XFS_DIFLAG2_VERITY;
++
++ xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
++ xfs_trans_set_sync(tp);
++
++ error = xfs_trans_commit(tp);
++ xfs_iunlock(ip, XFS_ILOCK_EXCL);
++ return error;
++}
+
+/*
+ * Prepare to enable fsverity by clearing old metadata.
@@ fs/xfs/xfs_fsverity.c: xfs_fsverity_is_file_data(
+ if (IS_DAX(inode) || ip->i_diflags2 & XFS_DIFLAG2_DAX)
+ return -EINVAL;
+
++ /*
++ * fs-verity stores the Merkle tree past EOF in units of the filesystem
++ * block size, so it cannot support realtime files whose allocation unit
++ * (extent size) is larger than the block size.
++ */
++ if (xfs_inode_has_bigrtalloc(ip))
++ return -EINVAL;
++
+ if (inode->i_size > XFS_FSVERITY_LARGEST_FILE)
+ return -EFBIG;
+
@@ fs/xfs/xfs_fsverity.c: xfs_fsverity_is_file_data(
+ xfs_assert_ilocked(ip, XFS_IOLOCK_EXCL);
+
+ /* fs-verity failed, just cleanup */
-+ if (desc == NULL) {
-+ error = xfs_fsverity_delete_metadata(ip);
++ if (desc == NULL)
+ goto out;
-+ }
+
+ error = xfs_fsverity_write_descriptor(file, desc, desc_size,
+ merkle_tree_size);
@@ fs/xfs/xfs_fsverity.c: xfs_fsverity_is_file_data(
+ if (error) {
+ int error2;
+
-+ error2 = xfs_fsverity_delete_metadata(ip);
++ error2 = xfs_fsverity_reset_inode(ip);
+ if (error2)
+ xfs_alert(ip->i_mount,
+"ino 0x%llx failed to clean up new fsverity metadata, err %d",
@@ fs/xfs/xfs_fsverity.c: xfs_fsverity_is_file_data(
+ generic_readahead_merkle_tree(inode, index, nr_pages);
+}
+
-+/*
-+ * Write a merkle tree block.
-+ */
-+static int
-+xfs_fsverity_write_merkle(
-+ struct file *file,
++static inline bool
++xfs_fsverity_is_hashes_of_zeroed_blocks(
++ struct xfs_inode *ip,
+ const void *buf,
-+ u64 pos,
+ unsigned int size,
+ const u8 *zero_digest,
+ unsigned int digest_size)
+{
-+ struct inode *inode = file_inode(file);
-+ struct xfs_inode *ip = XFS_I(inode);
-+ loff_t position = pos +
-+ xfs_fsverity_metadata_offset(ip);
-+
-+ if (position + size > inode->i_sb->s_maxbytes)
-+ return -EFBIG;
-+
+ /*
+ * If this is a block full of hashes of zeroed blocks, don't bother
+ * storing the block. We can synthesize them later.
@@ fs/xfs/xfs_fsverity.c: xfs_fsverity_is_file_data(
+ *
+ * Iomap won't know about these empty blocks.
+ */
-+ if (size == ip->i_mount->m_sb.sb_blocksize &&
-+ /*
-+ * First digest is zero_digest
-+ */
-+ memcmp(buf, zero_digest, digest_size) == 0 &&
-+ /*
-+ * Every digest is same as previous, thus all are
-+ * zero_digest
-+ */
-+ memcmp(buf + digest_size, buf, size - digest_size) == 0)
++ if (size != ip->i_mount->m_sb.sb_blocksize)
++ return false;
++ /*
++ * First digest is zero_digest
++ */
++ if (memcmp(buf, zero_digest, digest_size))
++ return false;
++ /*
++ * Every digest is same as previous, thus all are
++ * zero_digest
++ */
++ return memcmp(buf + digest_size, buf, size - digest_size) == 0;
++}
++
++/*
++ * Write a merkle tree block.
++ */
++static int
++xfs_fsverity_write_merkle(
++ struct file *file,
++ const void *buf,
++ u64 pos,
++ unsigned int size,
++ const u8 *zero_digest,
++ unsigned int digest_size)
++{
++ struct inode *inode = file_inode(file);
++ struct xfs_inode *ip = XFS_I(inode);
++ loff_t position = pos +
++ xfs_fsverity_metadata_offset(ip);
++
++ if (position + size > inode->i_sb->s_maxbytes)
++ return -EFBIG;
++
++ if (xfs_fsverity_is_hashes_of_zeroed_blocks(ip, buf, size, zero_digest,
++ digest_size))
+ return 0;
+
+ return iomap_fsverity_write(file, position, size, buf,
@@ fs/xfs/xfs_fsverity.h
#include "xfs_platform.h"
#include <linux/iomap.h>
+#include <linux/fsverity.h>
+ #include <linux/mempool.h>
#ifdef CONFIG_FS_VERITY
+extern const struct fsverity_operations xfs_fsverity_ops;
+ int xfs_fsverity_init(void);
+ void xfs_fsverity_exit(void);
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 ##
@@ fs/xfs/xfs_message.c: xfs_warn_experimental(
15: 78214f0c18ed = 16: 00314b4a38e2 xfs: initialize fs-verity on file open
16: 1cda98e462f0 = 17: d37e9d9a991e xfs: add fs-verity ioctls
17: c772780887b6 = 18: c21e90b7ac09 xfs: advertise fs-verity being available on filesystem
18: 2a1811e69360 ! 19: 6efa9e6690ee xfs: check and repair the verity inode flag state
@@ Commit message
opening the file, so clearing the flag will not compromise that model.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
- Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
+ Reviewed-by: Christoph Hellwig <hch@lst.de>
## fs/xfs/scrub/common.c ##
@@
@@ fs/xfs/scrub/common.c: xchk_inode_count_blocks(
+ break;
+ case -ENODATA:
+ case -EMSGSIZE:
-+ case -EINVAL:
+ case -EFSCORRUPTED:
-+ case -EFBIG:
+ case -ERANGE:
+ case -EBADMSG:
+ /*
19: 942e4a193836 = 20: e01d0c1aa284 xfs: introduce health state for corrupted fsverity metadata
20: 94fdc1d0ed15 = 21: 0ebd5899bc53 xfs: enable ro-compat fs-verity flag
--
2.54.0
next reply other threads:[~2026-10-02 22:37 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-02 22:36 Andrey Albershteyn [this message]
2026-10-02 22:36 ` [PATCH v17 01/21] fsverity: report validation errors through fserror to fsnotify Andrey Albershteyn
2026-10-02 22:36 ` [PATCH v17 02/21] fsverity: expose ensure_fsverity_info() Andrey Albershteyn
2026-10-02 22:36 ` [PATCH v17 03/21] fsverity: pass digest size and hash of the all-zeroes block to ->write Andrey Albershteyn
2026-10-02 22:36 ` [PATCH v17 04/21] fsverity: hoist pagecache_read from f2fs/ext4 to fsverity Andrey Albershteyn
2026-10-02 22:36 ` [PATCH v17 05/21] fsverity: don't allow setting DAX file attribute on fsverity files Andrey Albershteyn
2026-10-02 22:36 ` [PATCH v17 06/21] fsverity: hoist statx reporting of fs-verity flag Andrey Albershteyn
2026-10-02 22:36 ` [PATCH v17 07/21] xfs: introduce fsverity on-disk changes Andrey Albershteyn
2026-10-02 22:36 ` [PATCH v17 08/21] xfs: don't allow to enable DAX on fs-verity sealed inode Andrey Albershteyn
2026-10-02 22:36 ` [PATCH v17 09/21] xfs: disable direct read path for fs-verity files Andrey Albershteyn
2026-10-02 22:36 ` [PATCH v17 10/21] xfs: don't report dio_mem_align and dio_offset_align for fsverity files Andrey Albershteyn
2026-10-02 22:36 ` [PATCH v17 11/21] xfs: handle fsverity I/O in write/read path Andrey Albershteyn
2026-10-02 22:36 ` [PATCH v17 12/21] xfs: use read ioend for fsverity data verification Andrey Albershteyn
2026-10-02 22:36 ` [PATCH v17 13/21] xfs: add XFS_BMAPI_UNWRITTEN to unmap unwritten extents in __xfs_bunmapi() Andrey Albershteyn
2026-10-02 22:36 ` [PATCH v17 14/21] xfs: don't remove written extents past EOF on fsverity inodes Andrey Albershteyn
2026-10-02 22:36 ` [PATCH v17 15/21] xfs: add fs-verity support Andrey Albershteyn
2026-10-05 17:18 ` Andrey Albershteyn
2026-10-05 21:12 ` Darrick J. Wong
2026-10-06 9:03 ` Andrey Albershteyn
2026-10-02 22:36 ` [PATCH v17 16/21] xfs: initialize fs-verity on file open Andrey Albershteyn
2026-10-02 22:36 ` [PATCH v17 17/21] xfs: add fs-verity ioctls Andrey Albershteyn
2026-10-02 22:36 ` [PATCH v17 18/21] xfs: advertise fs-verity being available on filesystem Andrey Albershteyn
2026-10-02 22:37 ` [PATCH v17 19/21] xfs: check and repair the verity inode flag state Andrey Albershteyn
2026-10-02 22:37 ` [PATCH v17 20/21] xfs: introduce health state for corrupted fsverity metadata Andrey Albershteyn
2026-10-02 22:37 ` [PATCH v17 21/21] xfs: enable ro-compat fs-verity flag Andrey Albershteyn
2026-10-02 23:25 ` [PATCH v17 00/21] fs-verity support for XFS with post EOF merkle tree Eric Biggers
2026-10-03 12:07 ` Carlos Maiolino
2026-10-05 11:26 ` Andrey Albershteyn
2026-10-05 13:30 ` Eric Biggers
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261002223705.2175542-1-aalbersh@kernel.org \
--to=aalbersh@kernel.org \
--cc=cem@kernel.org \
--cc=david@fromorbit.com \
--cc=djwong@kernel.org \
--cc=ebiggers@kernel.org \
--cc=fsverity@lists.linux.dev \
--cc=hch@lst.de \
--cc=linux-btrfs@vger.kernel.org \
--cc=linux-ext4@vger.kernel.org \
--cc=linux-f2fs-devel@lists.sourceforge.net \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-unionfs@vger.kernel.org \
--cc=linux-xfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox