Linux XFS filesystem development
 help / color / mirror / Atom feed
* [PATCH v18 00/15] fs-verity support for XFS with post EOF merkle tree
@ 2026-11-02 14:41 Andrey Albershteyn
  2026-11-02 14:41 ` [PATCH v18 01/15] xfs: introduce fsverity on-disk changes Andrey Albershteyn
                   ` (14 more replies)
  0 siblings, 15 replies; 31+ messages in thread
From: Andrey Albershteyn @ 2026-11-02 14:41 UTC (permalink / raw)
  To: ebiggers, hch, Carlos Maiolino, fsverity, linux-xfs
  Cc: Andrey Albershteyn, linux-fsdevel, david

Hi all,

This is next revision of fsverity for XFS.

Patches without review:
[PATCH v18 06/15] xfs: use read ioend for fsverity data verification

This series based on v7.4-rc1

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

v17:
https://lore.kernel.org/fsverity/20261002223705.2175542-1-aalbersh@kernel.org/T/#u

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

To: djwong@kernel.org
To: ebiggers@kernel.org
To: hch@lst.de
To: Carlos Maiolino <cem@kernel.org>
To: fsverity@lists.linux.dev
To: linux-xfs@vger.kernel.org

Cc: linux-fsdevel@vger.kernel.org
Cc: david@fromorbit.com

---
Changes in v18:
- Rebase to latest origin/for-next and drop core fsverity patches
- Move truncate_inode_pages() before xfs_trans_alloc()
- Move xfs_fsverity_metadata_offset() to libxfs as used in xfs_bmap.c
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 (13):
  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/xfs/Makefile                |   2 +
 fs/xfs/libxfs/xfs_bmap.c       |  14 +-
 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/libxfs/xfs_verity.c     |  20 ++
 fs/xfs/libxfs/xfs_verity.h     |  12 +
 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              |  48 +++-
 fs/xfs/xfs_bmap_util.c         |  31 ++-
 fs/xfs/xfs_file.c              |  71 +++--
 fs/xfs/xfs_fsverity.c          | 482 +++++++++++++++++++++++++++++++++
 fs/xfs/xfs_fsverity.h          |  42 +++
 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             |  41 ++-
 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 ++-
 32 files changed, 997 insertions(+), 63 deletions(-)
 create mode 100644 fs/xfs/libxfs/xfs_verity.c
 create mode 100644 fs/xfs/libxfs/xfs_verity.h
 create mode 100644 fs/xfs/xfs_fsverity.c
 create mode 100644 fs/xfs/xfs_fsverity.h

Range-diff against v17:
 1:  c14aea60fb61 <  -:  ------------ fsverity: report validation errors through fserror to fsnotify
 2:  ba2ec9993a12 <  -:  ------------ fsverity: expose ensure_fsverity_info()
 3:  68694ea8ba0d <  -:  ------------ fsverity: pass digest size and hash of the all-zeroes block to ->write
 4:  5732f007e676 <  -:  ------------ fsverity: hoist pagecache_read from f2fs/ext4 to fsverity
 5:  9928ceefe211 <  -:  ------------ fsverity: don't allow setting DAX file attribute on fsverity files
 6:  8f866da8730c <  -:  ------------ fsverity: hoist statx reporting of fs-verity flag
 7:  d93e466c36fd =  1:  b04517813858 xfs: introduce fsverity on-disk changes
 8:  4bcf1275fa38 =  2:  217a30d22c06 xfs: don't allow to enable DAX on fs-verity sealed inode
 9:  082d5f39ae5a =  3:  ac5bfd8422db xfs: disable direct read path for fs-verity files
10:  21b92f51fd5e =  4:  7a55ff638ffd xfs: don't report dio_mem_align and dio_offset_align for fsverity files
11:  929a7172c341 !  5:  252fd0205997 xfs: handle fsverity I/O in write/read path
    @@ Commit message
         Reviewed-by: Christoph Hellwig <hch@lst.de>
     
      ## fs/xfs/Makefile ##
    -@@ fs/xfs/Makefile: 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/Makefile: xfs-y				+= $(addprefix libxfs/, \
    + 				   xfs_trans_resv.o \
    + 				   xfs_trans_space.o \
    + 				   xfs_types.o \
    ++				   xfs_verity.o \
    + 				   )
    + # xfs_rtbitmap is shared with libxfs
    + xfs-$(CONFIG_XFS_RT)		+= $(addprefix libxfs/, \
     
      ## fs/xfs/libxfs/xfs_bmap.c ##
     @@
      #include "xfs_inode_util.h"
      #include "xfs_rtgroup.h"
      #include "xfs_zone_alloc.h"
    -+#include "xfs_fsverity.h"
    -+#include <linux/fsverity.h>
    ++#include "xfs_verity.h"
      
      struct kmem_cache		*xfs_bmap_intent_cache;
      
    @@ fs/xfs/libxfs/xfs_bmap.c: xfs_bmapi_convert_one_delalloc(
      	xfs_bmbt_to_iomap(ip, iomap, &bma.got, 0, flags,
      				xfs_iomap_inode_sequence(ip, flags));
     
    + ## fs/xfs/libxfs/xfs_verity.c (new) ##
    +@@
    ++// SPDX-License-Identifier: GPL-2.0
    ++/*
    ++ * Copyright (C) 2026 Red Hat, Inc.
    ++ */
    ++#include "xfs_platform.h"
    ++#include "xfs_fs.h"
    ++#include "xfs_shared.h"
    ++#include "xfs_format.h"
    ++#include "xfs_log_format.h"
    ++#include "xfs_trans_resv.h"
    ++#include "xfs_mount.h"
    ++#include "xfs_inode.h"
    ++#include "xfs_verity.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/libxfs/xfs_verity.h (new) ##
    +@@
    ++// SPDX-License-Identifier: GPL-2.0
    ++/*
    ++ * Copyright (C) 2026 Red Hat, Inc.
    ++ */
    ++#ifndef __XFS_VERITY_H__
    ++#define __XFS_VERITY_H__
    ++
    ++#include "xfs_platform.h"
    ++
    ++loff_t xfs_fsverity_metadata_offset(const struct xfs_inode *ip);
    ++
    ++#endif	/* __XFS_VERITY_H__ */
    +
      ## fs/xfs/xfs_aops.c ##
     @@
      #include "xfs_ioend.h"
    @@ fs/xfs/xfs_aops.c: xfs_vm_writepages(
      }
      
     
    - ## fs/xfs/xfs_fsverity.c (new) ##
    -@@
    -+// SPDX-License-Identifier: GPL-2.0
    -+/*
    -+ * Copyright (C) 2026 Red Hat, Inc.
    -+ */
    -+#include "xfs_platform.h"
    -+#include "xfs_fs.h"
    -+#include "xfs_shared.h"
    -+#include "xfs_format.h"
    -+#include "xfs_log_format.h"
    -+#include "xfs_trans_resv.h"
    -+#include "xfs_mount.h"
    -+#include "xfs_inode.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) ##
    -@@
    -+// 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 ##
     @@ fs/xfs/xfs_inode.h: static inline bool xfs_inode_can_sw_atomic_write(const struct xfs_inode *ip)
       */
    @@ fs/xfs/xfs_iomap.c
      #include "xfs_rtbitmap.h"
      #include "xfs_icache.h"
      #include "xfs_zone_alloc.h"
    -+#include "xfs_fsverity.h"
    ++#include "xfs_verity.h"
     +#include <linux/fsverity.h>
      
      #define XFS_ALLOC_ALIGN(mp, off) \
    @@ fs/xfs/xfs_iomap.c: xfs_zoned_direct_write_iomap_begin(
      	return 0;
      }
      
    +@@ fs/xfs/xfs_iomap.c: xfs_zoned_fill_srcmap(
    + 	xfs_fileoff_t		offset_fsb,
    + 	xfs_fileoff_t		*end_fsb,
    + 	unsigned		flags,
    +-	struct iomap		*srcmap)
    ++	struct iomap		*srcmap,
    ++	u16			iomap_flags)
    + {
    + 	struct xfs_bmbt_irec	smap;
    + 	struct xfs_iext_cursor	scur;
    +@@ fs/xfs/xfs_iomap.c: xfs_zoned_fill_srcmap(
    + 	 */
    + 	xfs_trim_extent(&smap, offset_fsb, *end_fsb - offset_fsb);
    + 	*end_fsb = min(*end_fsb, smap.br_startoff + smap.br_blockcount);
    +-	return xfs_bmbt_to_iomap(ip, srcmap, &smap, flags, 0,
    ++	return xfs_bmbt_to_iomap(ip, srcmap, &smap, flags, iomap_flags,
    + 			xfs_iomap_inode_sequence(ip, 0));
    + }
    + 
     @@ fs/xfs/xfs_iomap.c: xfs_zoned_buffered_write_iomap_begin(
      	loff_t			count,
      	unsigned		flags,
    @@ fs/xfs/xfs_iomap.c: xfs_zoned_buffered_write_iomap_begin(
      	xfs_filblks_t		count_fsb;
      	xfs_extlen_t		indlen;
     @@ fs/xfs/xfs_iomap.c: xfs_zoned_buffered_write_iomap_begin(
    - 				smap.br_startoff + smap.br_blockcount);
    - 			xfs_trim_extent(&smap, offset_fsb,
    - 					end_fsb - offset_fsb);
    --			error = xfs_bmbt_to_iomap(ip, srcmap, &smap, flags, 0,
    -+			error = xfs_bmbt_to_iomap(ip, srcmap, &smap, flags,
    -+					iomap_flags,
    - 					xfs_iomap_inode_sequence(ip, 0));
    - 			if (error)
    - 				goto out_unlock;
    + 	    !IS_ALIGNED(offset + count, mp->m_sb.sb_blocksize) ||
    + 	    (flags & IOMAP_ZERO)) {
    + 		error = xfs_zoned_fill_srcmap(ip, offset_fsb, &end_fsb, flags,
    +-				srcmap);
    ++				srcmap, iomap_flags);
    + 		if (error)
    + 			goto out_unlock;
    + 	}
     @@ fs/xfs/xfs_iomap.c: xfs_zoned_buffered_write_iomap_begin(
      	if (!ip->i_cowfp)
      		xfs_ifork_init_cow(ip);
12:  db144b392a91 !  6:  aea6b162458f xfs: use read ioend for fsverity data verification
    @@ Commit message
     
         Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
     
    + ## fs/xfs/Makefile ##
    +@@ fs/xfs/Makefile: 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/xfs_aops.c ##
    -@@
    - #include "xfs_zone_alloc.h"
    - #include "xfs_rtgroup.h"
    - #include "xfs_fsverity.h"
    -+#include <linux/fsverity.h>
    - 
    - struct xfs_writepage_ctx {
    - 	struct iomap_writepage_ctx ctx;
     @@ fs/xfs/xfs_aops.c: xfs_bio_submit_read(
      {
      	xfs_ioend_submit_read(iter->inode, ctx->read_ctx,
    @@ fs/xfs/xfs_file.c: xfs_dio_read_bounce_submit_io(
      
      static const struct iomap_dio_ops xfs_dio_read_bounce_ops = {
     
    - ## fs/xfs/xfs_fsverity.c ##
    + ## fs/xfs/xfs_fsverity.c (new) ##
     @@
    - #include <linux/fsverity.h>
    - #include <linux/iomap.h>
    - 
    ++// SPDX-License-Identifier: GPL-2.0
    ++/*
    ++ * Copyright (C) 2026 Red Hat, Inc.
    ++ */
    ++#include "xfs_platform.h"
    ++#include "xfs_fs.h"
    ++#include "xfs_shared.h"
    ++#include "xfs_format.h"
    ++#include "xfs_log_format.h"
    ++#include "xfs_trans_resv.h"
    ++#include "xfs_mount.h"
    ++#include "xfs_inode.h"
    ++#include "xfs_fsverity.h"
    ++#include <linux/fsverity.h>
    ++#include <linux/iomap.h>
    ++
     +struct kmem_cache *xfs_fsverity_ioend_cache;
     +mempool_t xfs_fsverity_ioend_pool;
     +
    @@ fs/xfs/xfs_fsverity.c
     +{
     +	mempool_exit(&xfs_fsverity_ioend_pool);
     +}
    -+
    - loff_t
    - xfs_fsverity_metadata_offset(
    - 	const struct xfs_inode	*ip)
    - {
    - 	return round_up(i_size_read(VFS_IC(ip)), XFS_FSVERITY_START_ALIGN);
    - }
     +
     +bool
     +xfs_fsverity_is_file_data(
    @@ fs/xfs/xfs_fsverity.c
     +			offset < xfs_fsverity_metadata_offset(ip);
     +}
     
    - ## fs/xfs/xfs_fsverity.h ##
    + ## fs/xfs/xfs_fsverity.h (new) ##
     @@
    - #define __XFS_FSVERITY_H__
    - 
    - #include "xfs_platform.h"
    ++// SPDX-License-Identifier: GPL-2.0
    ++/*
    ++ * Copyright (C) 2026 Red Hat, Inc.
    ++ */
    ++#ifndef __XFS_FSVERITY_H__
    ++#define __XFS_FSVERITY_H__
    ++
    ++#include "xfs_platform.h"
    ++#include "xfs_verity.h"
     +#include <linux/iomap.h>
     +#include <linux/mempool.h>
    - 
    - #ifdef CONFIG_FS_VERITY
    ++
    ++#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
    ++#else
     +static inline int xfs_fsverity_init(void)
     +{
     +	return 0;
    @@ fs/xfs/xfs_fsverity.h
     +static inline void xfs_fsverity_exit(void)
     +{
     +}
    - 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	/* CONFIG_FS_VERITY */
    ++
     +struct xfs_fsverity_ioend {
     +	struct iomap_ioend	*ioend;
     +	struct work_struct	work;
    @@ fs/xfs/xfs_fsverity.h
     +extern struct kmem_cache *xfs_fsverity_ioend_cache;
     +extern mempool_t xfs_fsverity_ioend_pool;
     +
    - #endif	/* __XFS_FSVERITY_H__ */
    ++#endif	/* __XFS_FSVERITY_H__ */
     
      ## fs/xfs/xfs_ioend.c ##
     @@
13:  5f00c1287b5e =  7:  234329f5df02 xfs: add XFS_BMAPI_UNWRITTEN to unmap unwritten extents in __xfs_bunmapi()
14:  9a82d542d940 =  8:  502c28c54708 xfs: don't remove written extents past EOF on fsverity inodes
15:  420fb1a97664 !  9:  00a5a23c1b4a xfs: add fs-verity support
    @@ fs/xfs/xfs_fsverity.c: xfs_fsverity_is_file_data(
     +	int			error;
     +
     +	xfs_ilock(ip, XFS_MMAPLOCK_EXCL);
    ++	truncate_inode_pages(VFS_I(ip)->i_mapping, XFS_ISIZE(ip));
    ++
     +	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp);
     +	if (error) {
     +		xfs_iunlock(ip, XFS_MMAPLOCK_EXCL);
     +		return error;
     +	}
     +
    -+	truncate_inode_pages(VFS_I(ip)->i_mapping, XFS_ISIZE(ip));
    -+
     +	xfs_ilock(ip, XFS_ILOCK_EXCL);
     +	xfs_trans_ijoin(tp, ip, 0);
     +
    @@ fs/xfs/xfs_fsverity.c: xfs_fsverity_is_file_data(
     
      ## fs/xfs/xfs_fsverity.h ##
     @@
    - 
      #include "xfs_platform.h"
    + #include "xfs_verity.h"
      #include <linux/iomap.h>
     +#include <linux/fsverity.h>
      #include <linux/mempool.h>
    @@ fs/xfs/xfs_fsverity.h
     +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);
     
      ## fs/xfs/xfs_message.c ##
     @@ fs/xfs/xfs_message.c: xfs_warn_experimental(
16:  00314b4a38e2 = 10:  e6c2e7ef30ae xfs: initialize fs-verity on file open
17:  d37e9d9a991e = 11:  015c18cfb5a4 xfs: add fs-verity ioctls
18:  c21e90b7ac09 = 12:  37b40dc83dff xfs: advertise fs-verity being available on filesystem
19:  6efa9e6690ee ! 13:  f4f2f6cb1db0 xfs: check and repair the verity inode flag state
    @@ fs/xfs/scrub/inode_repair.c: xrep_dinode_core(
      	error = xchk_trans_alloc(sc, 0);
      	if (error)
      		return error;
    -@@ fs/xfs/scrub/inode_repair.c: xrep_inode_unlinked(
    - 	return 0;
    - }
    +@@ fs/xfs/scrub/inode_repair.c: xrep_inode_reset_dquots(
    + # define xrep_inode_reset_dquots(sc)		(0)
    + #endif
      
     +/*
     + * If this file is a fsverity file, xchk_prepare_iscrub or xrep_dinode_core
20:  e01d0c1aa284 = 14:  d7502ab4649b xfs: introduce health state for corrupted fsverity metadata
21:  0ebd5899bc53 = 15:  2181d0402e98 xfs: enable ro-compat fs-verity flag
-- 
2.54.0


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH v18 01/15] xfs: introduce fsverity on-disk changes
  2026-11-02 14:41 [PATCH v18 00/15] fs-verity support for XFS with post EOF merkle tree Andrey Albershteyn
@ 2026-11-02 14:41 ` Andrey Albershteyn
  2026-11-02 14:41 ` [PATCH v18 02/15] xfs: don't allow to enable DAX on fs-verity sealed inode Andrey Albershteyn
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 31+ messages in thread
From: Andrey Albershteyn @ 2026-11-02 14:41 UTC (permalink / raw)
  To: ebiggers, hch, Carlos Maiolino, fsverity, linux-xfs
  Cc: Andrey Albershteyn, linux-fsdevel, david, Darrick J. Wong

Introduce 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.

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/libxfs/xfs_format.h     | 30 +++++++++++++++++++++++++++++-
 fs/xfs/libxfs/xfs_inode_buf.c  |  8 ++++++++
 fs/xfs/libxfs/xfs_inode_util.c |  5 ++++-
 fs/xfs/libxfs/xfs_sb.c         |  2 ++
 fs/xfs/xfs_iops.c              |  5 ++++-
 fs/xfs/xfs_mount.h             |  2 ++
 6 files changed, 49 insertions(+), 3 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index 469e879149ac..e1f50ad18f0b 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -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 | \
@@ -1234,16 +1235,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)
 {
@@ -2031,4 +2037,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 synthesis in the iomap.
+ */
+#define XFS_FSVERITY_START_ALIGN	(65536)
+
+
 #endif /* __XFS_FORMAT_H__ */
diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
index 8c9d296ebfe9..13042e1eaf35 100644
--- a/fs/xfs/libxfs/xfs_inode_buf.c
+++ b/fs/xfs/libxfs/xfs_inode_buf.c
@@ -758,6 +758,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)
diff --git a/fs/xfs/libxfs/xfs_inode_util.c b/fs/xfs/libxfs/xfs_inode_util.c
index f486b23a9b52..a717b19558af 100644
--- a/fs/xfs/libxfs/xfs_inode_util.c
+++ b/fs/xfs/libxfs/xfs_inode_util.c
@@ -73,7 +73,8 @@ xfs_flags2diflags2(
 	uint64_t		di_flags2 =
 		(ip->i_diflags2 & (XFS_DIFLAG2_REFLINK |
 				   XFS_DIFLAG2_BIGTIME |
-				   XFS_DIFLAG2_NREXT64));
+				   XFS_DIFLAG2_NREXT64 |
+				   XFS_DIFLAG2_VERITY));
 
 	if (xflags & FS_XFLAG_DAX)
 		di_flags2 |= XFS_DIFLAG2_DAX;
@@ -125,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))
diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c
index ce44123c98ce..7629fc3f499f 100644
--- a/fs/xfs/libxfs/xfs_sb.c
+++ b/fs/xfs/libxfs/xfs_sb.c
@@ -164,6 +164,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)
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index d307ec97fac8..3f8b8f79a4db 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -1415,12 +1415,15 @@ 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
 	 * the VFS, so we cannot mask off S_DAX in i_flags.
 	 */
-	inode->i_flags &= ~(S_IMMUTABLE | S_APPEND | S_SYNC | S_NOATIME);
+	inode->i_flags &=
+		~(S_IMMUTABLE | S_APPEND | S_SYNC | S_NOATIME | S_VERITY);
 	inode->i_flags |= flags;
 }
 
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index cbcfb89c67a4..700964048587 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -403,6 +403,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 */
@@ -460,6 +461,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)
 {
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v18 02/15] xfs: don't allow to enable DAX on fs-verity sealed inode
  2026-11-02 14:41 [PATCH v18 00/15] fs-verity support for XFS with post EOF merkle tree Andrey Albershteyn
  2026-11-02 14:41 ` [PATCH v18 01/15] xfs: introduce fsverity on-disk changes Andrey Albershteyn
@ 2026-11-02 14:41 ` Andrey Albershteyn
  2026-11-02 14:41 ` [PATCH v18 03/15] xfs: disable direct read path for fs-verity files Andrey Albershteyn
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 31+ messages in thread
From: Andrey Albershteyn @ 2026-11-02 14:41 UTC (permalink / raw)
  To: ebiggers, hch, Carlos Maiolino, fsverity, linux-xfs
  Cc: Andrey Albershteyn, linux-fsdevel, david, Darrick J. Wong

fs-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.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
---
 fs/xfs/xfs_iops.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index 3f8b8f79a4db..b25a0c2fbd2a 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -1387,6 +1387,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)
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v18 03/15] xfs: disable direct read path for fs-verity files
  2026-11-02 14:41 [PATCH v18 00/15] fs-verity support for XFS with post EOF merkle tree Andrey Albershteyn
  2026-11-02 14:41 ` [PATCH v18 01/15] xfs: introduce fsverity on-disk changes Andrey Albershteyn
  2026-11-02 14:41 ` [PATCH v18 02/15] xfs: don't allow to enable DAX on fs-verity sealed inode Andrey Albershteyn
@ 2026-11-02 14:41 ` Andrey Albershteyn
  2026-11-02 14:41 ` [PATCH v18 04/15] xfs: don't report dio_mem_align and dio_offset_align for fsverity files Andrey Albershteyn
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 31+ messages in thread
From: Andrey Albershteyn @ 2026-11-02 14:41 UTC (permalink / raw)
  To: ebiggers, hch, Carlos Maiolino, fsverity, linux-xfs
  Cc: Andrey Albershteyn, linux-fsdevel, david, Darrick J. Wong

The 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.

Add a fall back to buffered I/O at two place, in a common fast path and
latter when lock is acquired. The second check prevents TOCTOU issue
with reading fsverity_active() status and resetting IOCB_DIRECT flag.

If one thread saw fsverity_active() to be false, and then second thread
acquired XFS_IOLOCK_EXCL and enabled fsverity. The first thread will go
through the DIO path.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 fs/xfs/xfs_file.c | 61 +++++++++++++++++++++++++++++++----------------
 1 file changed, 41 insertions(+), 20 deletions(-)

diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index 7d0c8a197575..f0d000272521 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -38,6 +38,7 @@
 #include <linux/mount.h>
 #include <linux/filelock.h>
 #include <linux/bio-integrity.h>
+#include <linux/fsverity.h>
 
 static const struct vm_operations_struct xfs_file_vm_ops;
 
@@ -231,6 +232,25 @@ static const struct iomap_dio_ops xfs_dio_read_bounce_ops = {
 	.bio_set	= &iomap_ioend_bioset,
 };
 
+STATIC ssize_t
+xfs_file_buffered_read(
+	struct kiocb		*iocb,
+	struct iov_iter		*to)
+{
+	struct xfs_inode	*ip = XFS_I(file_inode(iocb->ki_filp));
+	ssize_t			ret;
+
+	trace_xfs_file_buffered_read(iocb, to);
+
+	ret = xfs_ilock_iocb(iocb, XFS_IOLOCK_SHARED);
+	if (ret)
+		return ret;
+	ret = generic_file_read_iter(iocb, to);
+	xfs_iunlock(ip, XFS_IOLOCK_SHARED);
+
+	return ret;
+}
+
 STATIC ssize_t
 xfs_file_dio_read(
 	struct kiocb		*iocb,
@@ -249,6 +269,17 @@ xfs_file_dio_read(
 	ret = xfs_ilock_iocb(iocb, XFS_IOLOCK_SHARED);
 	if (ret)
 		return ret;
+
+	/*
+	 * Re-check verity status after acquiring lock. This prevents TOCTOU in
+	 * xfs_file_read_iter() while falling back from DIO to buffered I/O as
+	 * now we are holding a lock
+	 */
+	if (fsverity_active(VFS_I(ip))) {
+		xfs_iunlock(ip, XFS_IOLOCK_SHARED);
+		iocb->ki_flags &= ~IOCB_DIRECT;
+		return xfs_file_buffered_read(iocb, to);
+	}
 	if (mapping_stable_writes(iocb->ki_filp->f_mapping)) {
 		ret = iomap_dio_rw(iocb, to, &xfs_read_iomap_ops,
 				&xfs_dio_read_bounce_ops, 0, NULL, 0);
@@ -268,7 +299,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);
@@ -286,25 +318,6 @@ xfs_file_dax_read(
 	return ret;
 }
 
-STATIC ssize_t
-xfs_file_buffered_read(
-	struct kiocb		*iocb,
-	struct iov_iter		*to)
-{
-	struct xfs_inode	*ip = XFS_I(file_inode(iocb->ki_filp));
-	ssize_t			ret;
-
-	trace_xfs_file_buffered_read(iocb, to);
-
-	ret = xfs_ilock_iocb(iocb, XFS_IOLOCK_SHARED);
-	if (ret)
-		return ret;
-	ret = generic_file_read_iter(iocb, to);
-	xfs_iunlock(ip, XFS_IOLOCK_SHARED);
-
-	return ret;
-}
-
 STATIC ssize_t
 xfs_file_read_iter(
 	struct kiocb		*iocb,
@@ -319,6 +332,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)
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v18 04/15] xfs: don't report dio_mem_align and dio_offset_align for fsverity files
  2026-11-02 14:41 [PATCH v18 00/15] fs-verity support for XFS with post EOF merkle tree Andrey Albershteyn
                   ` (2 preceding siblings ...)
  2026-11-02 14:41 ` [PATCH v18 03/15] xfs: disable direct read path for fs-verity files Andrey Albershteyn
@ 2026-11-02 14:41 ` Andrey Albershteyn
  2026-11-03  9:23   ` Christoph Hellwig
  2026-11-02 14:41 ` [PATCH v18 05/15] xfs: handle fsverity I/O in write/read path Andrey Albershteyn
                   ` (10 subsequent siblings)
  14 siblings, 1 reply; 31+ messages in thread
From: Andrey Albershteyn @ 2026-11-02 14:41 UTC (permalink / raw)
  To: ebiggers, hch, Carlos Maiolino, fsverity, linux-xfs
  Cc: Andrey Albershteyn, linux-fsdevel, david, Darrick J. Wong

Sashiko.dev reported that while fsverity files falls back to the
buffered IO for Direct I/O, they should not report non-zero values in
dio_mem_align and dio_offset_align, meaning it's not supported.

The STATX_DIOALIGN | STATX_DIO_READ_ALIGN flags are used to explicitly
report if DIO is supported or not. They can not indicate that fallback
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>
---
 fs/xfs/xfs_iops.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index b25a0c2fbd2a..150bbd705807 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -35,6 +35,7 @@
 #include <linux/security.h>
 #include <linux/iversion.h>
 #include <linux/fiemap.h>
+#include <linux/fsverity.h>
 
 /*
  * Directories have different lock order w.r.t. mmap_lock compared to regular
@@ -579,6 +580,10 @@ xfs_report_dioalign(
 	struct block_device	*bdev = target->bt_bdev;
 
 	stat->result_mask |= STATX_DIOALIGN | STATX_DIO_READ_ALIGN;
+
+	if (fsverity_active(VFS_I(ip)))
+		return;
+
 	stat->dio_mem_align = bdev_dma_alignment(bdev) + 1;
 
 	/*
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v18 05/15] xfs: handle fsverity I/O in write/read path
  2026-11-02 14:41 [PATCH v18 00/15] fs-verity support for XFS with post EOF merkle tree Andrey Albershteyn
                   ` (3 preceding siblings ...)
  2026-11-02 14:41 ` [PATCH v18 04/15] xfs: don't report dio_mem_align and dio_offset_align for fsverity files Andrey Albershteyn
@ 2026-11-02 14:41 ` Andrey Albershteyn
  2026-11-03  9:37   ` Christoph Hellwig
  2026-11-02 14:41 ` [PATCH v18 06/15] xfs: use read ioend for fsverity data verification Andrey Albershteyn
                   ` (9 subsequent siblings)
  14 siblings, 1 reply; 31+ messages in thread
From: Andrey Albershteyn @ 2026-11-02 14:41 UTC (permalink / raw)
  To: ebiggers, hch, Carlos Maiolino, fsverity, linux-xfs
  Cc: Andrey Albershteyn, linux-fsdevel, david, Darrick J. Wong

For 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.

Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 fs/xfs/Makefile            |  1 +
 fs/xfs/libxfs/xfs_bmap.c   |  8 ++++++++
 fs/xfs/libxfs/xfs_verity.c | 20 +++++++++++++++++++
 fs/xfs/libxfs/xfs_verity.h | 12 +++++++++++
 fs/xfs/xfs_aops.c          | 36 ++++++++++++++++++++++++++++-----
 fs/xfs/xfs_inode.h         |  6 ++++++
 fs/xfs/xfs_iomap.c         | 41 ++++++++++++++++++++++++++++----------
 fs/xfs/xfs_iomap.h         |  5 +++--
 8 files changed, 111 insertions(+), 18 deletions(-)
 create mode 100644 fs/xfs/libxfs/xfs_verity.c
 create mode 100644 fs/xfs/libxfs/xfs_verity.h

diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
index 399a207f2d0e..cb7f71457ee9 100644
--- a/fs/xfs/Makefile
+++ b/fs/xfs/Makefile
@@ -59,6 +59,7 @@ xfs-y				+= $(addprefix libxfs/, \
 				   xfs_trans_resv.o \
 				   xfs_trans_space.o \
 				   xfs_types.o \
+				   xfs_verity.o \
 				   )
 # xfs_rtbitmap is shared with libxfs
 xfs-$(CONFIG_XFS_RT)		+= $(addprefix libxfs/, \
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index ca49bf4a50c5..a35a44cf8c63 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -41,6 +41,7 @@
 #include "xfs_inode_util.h"
 #include "xfs_rtgroup.h"
 #include "xfs_zone_alloc.h"
+#include "xfs_verity.h"
 
 struct kmem_cache		*xfs_bmap_intent_cache;
 
@@ -4404,6 +4405,9 @@ xfs_bmapi_convert_one_delalloc(
 	 * the extent.  Just return the real extent at this offset.
 	 */
 	if (!isnullstartblock(bma.got.br_startblock)) {
+		if (xfs_iflags_test(ip, XFS_VERITY_CONSTRUCTION) &&
+		    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));
 		if (seq)
@@ -4451,6 +4455,10 @@ 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) &&
+	    offset >= 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));
diff --git a/fs/xfs/libxfs/xfs_verity.c b/fs/xfs/libxfs/xfs_verity.c
new file mode 100644
index 000000000000..c1731b89a5a1
--- /dev/null
+++ b/fs/xfs/libxfs/xfs_verity.c
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2026 Red Hat, Inc.
+ */
+#include "xfs_platform.h"
+#include "xfs_fs.h"
+#include "xfs_shared.h"
+#include "xfs_format.h"
+#include "xfs_log_format.h"
+#include "xfs_trans_resv.h"
+#include "xfs_mount.h"
+#include "xfs_inode.h"
+#include "xfs_verity.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);
+}
diff --git a/fs/xfs/libxfs/xfs_verity.h b/fs/xfs/libxfs/xfs_verity.h
new file mode 100644
index 000000000000..db89d557edcd
--- /dev/null
+++ b/fs/xfs/libxfs/xfs_verity.h
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2026 Red Hat, Inc.
+ */
+#ifndef __XFS_VERITY_H__
+#define __XFS_VERITY_H__
+
+#include "xfs_platform.h"
+
+loff_t xfs_fsverity_metadata_offset(const struct xfs_inode *ip);
+
+#endif	/* __XFS_VERITY_H__ */
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
index c30e688cfc9f..19640e4e3ed1 100644
--- a/fs/xfs/xfs_aops.c
+++ b/fs/xfs/xfs_aops.c
@@ -23,6 +23,7 @@
 #include "xfs_ioend.h"
 #include "xfs_zone_alloc.h"
 #include "xfs_rtgroup.h"
+#include "xfs_fsverity.h"
 
 struct xfs_writepage_ctx {
 	struct iomap_writepage_ctx ctx;
@@ -172,12 +173,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
@@ -265,7 +270,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:
@@ -412,12 +418,16 @@ xfs_zoned_map_blocks(
 	xfs_filblks_t		count_fsb;
 	struct xfs_bmbt_irec	imap, del;
 	struct xfs_iext_cursor	icur;
+	u16			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;
+
 	/*
 	 * All dirty data must be covered by delalloc extents.  But truncate can
 	 * remove delalloc extents underneath us or reduce their size.
@@ -441,7 +451,7 @@ xfs_zoned_map_blocks(
 		imap.br_startblock = HOLESTARTBLOCK;
 		imap.br_state = XFS_EXT_NORM;
 		xfs_iunlock(ip, XFS_ILOCK_EXCL);
-		xfs_bmbt_to_iomap(ip, &wpc->iomap, &imap, 0, 0, 0);
+		xfs_bmbt_to_iomap(ip, &wpc->iomap, &imap, 0, iomap_flags, 0);
 		return 0;
 	}
 	end_fsb = min(end_fsb, imap.br_startoff + imap.br_blockcount);
@@ -454,7 +464,7 @@ xfs_zoned_map_blocks(
 	xfs_iunlock(ip, XFS_ILOCK_EXCL);
 
 	xfs_iomap_set_anon_write(ip, &wpc->iomap, offset,
-			XFS_FSB_TO_B(mp, count_fsb));
+			XFS_FSB_TO_B(mp, count_fsb), iomap_flags);
 	trace_xfs_zoned_map_blocks(ip, offset, wpc->iomap.length);
 	return 0;
 }
@@ -507,6 +517,22 @@ static const struct iomap_writeback_ops xfs_zoned_writeback_ops = {
 	.writeback_submit	= xfs_zoned_writeback_submit,
 };
 
+static int
+xfs_iomap_writepages(
+	struct xfs_inode		*ip,
+	struct iomap_writepage_ctx	*ctx)
+{
+	/*
+	 * 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))
+		ctx->iomap.flags |= IOMAP_F_FSVERITY;
+
+	return iomap_writepages(ctx);
+}
+
 STATIC int
 xfs_vm_writepages(
 	struct address_space	*mapping,
@@ -526,7 +552,7 @@ xfs_vm_writepages(
 		};
 		int				error;
 
-		error = iomap_writepages(&xc.ctx);
+		error = xfs_iomap_writepages(ip, &xc.ctx);
 		if (xc.open_zone)
 			xfs_open_zone_put(xc.open_zone);
 		return error;
@@ -539,7 +565,7 @@ xfs_vm_writepages(
 			},
 		};
 
-		return iomap_writepages(&wpc.ctx);
+		return xfs_iomap_writepages(ip, &wpc.ctx);
 	}
 }
 
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index 75eff68c1e39..034d3f6072a9 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -428,6 +428,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 | \
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index 329c745e3120..68fef6576442 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -32,6 +32,8 @@
 #include "xfs_rtbitmap.h"
 #include "xfs_icache.h"
 #include "xfs_zone_alloc.h"
+#include "xfs_verity.h"
+#include <linux/fsverity.h>
 
 #define XFS_ALLOC_ALIGN(mp, off) \
 	(((off) >> mp->m_allocsize_log) << mp->m_allocsize_log)
@@ -883,6 +885,9 @@ xfs_direct_write_iomap_begin(
 	if (flags & IOMAP_ATOMIC)
 		iomap_flags |= IOMAP_F_ATOMIC_BIO;
 
+	if (xfs_iflags_test(ip, XFS_VERITY_CONSTRUCTION))
+		iomap_flags |= IOMAP_F_FSVERITY;
+
 	/*
 	 * COW writes may allocate delalloc space or convert unwritten COW
 	 * extents, so we need to make sure to take the lock exclusively here.
@@ -1023,7 +1028,8 @@ 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;
 	}
@@ -1083,7 +1089,7 @@ xfs_zoned_direct_write_iomap_begin(
 			return error;
 	}
 
-	xfs_iomap_set_anon_write(ip, iomap, offset, length);
+	xfs_iomap_set_anon_write(ip, iomap, offset, length, 0);
 	return 0;
 }
 
@@ -1594,7 +1600,8 @@ xfs_zoned_fill_srcmap(
 	xfs_fileoff_t		offset_fsb,
 	xfs_fileoff_t		*end_fsb,
 	unsigned		flags,
-	struct iomap		*srcmap)
+	struct iomap		*srcmap,
+	u16			iomap_flags)
 {
 	struct xfs_bmbt_irec	smap;
 	struct xfs_iext_cursor	scur;
@@ -1615,7 +1622,7 @@ xfs_zoned_fill_srcmap(
 	 */
 	xfs_trim_extent(&smap, offset_fsb, *end_fsb - offset_fsb);
 	*end_fsb = min(*end_fsb, smap.br_startoff + smap.br_blockcount);
-	return xfs_bmbt_to_iomap(ip, srcmap, &smap, flags, 0,
+	return xfs_bmbt_to_iomap(ip, srcmap, &smap, flags, iomap_flags,
 			xfs_iomap_inode_sequence(ip, 0));
 }
 
@@ -1626,7 +1633,8 @@ xfs_zoned_buffered_write_iomap_begin(
 	loff_t			count,
 	unsigned		flags,
 	struct iomap		*iomap,
-	struct iomap		*srcmap)
+	struct iomap		*srcmap,
+	u16			iomap_flags)
 {
 	struct iomap_iter	*iter =
 		container_of(iomap, struct iomap_iter, iomap);
@@ -1636,7 +1644,6 @@ xfs_zoned_buffered_write_iomap_begin(
 	struct xfs_mount	*mp = ip->i_mount;
 	xfs_fileoff_t		offset_fsb = XFS_B_TO_FSBT(mp, offset);
 	xfs_fileoff_t		end_fsb = xfs_iomap_end_fsb(mp, offset, count);
-	u16			iomap_flags = IOMAP_F_SHARED;
 	unsigned int		lockmode = XFS_ILOCK_EXCL;
 	xfs_filblks_t		count_fsb;
 	xfs_extlen_t		indlen;
@@ -1687,7 +1694,7 @@ xfs_zoned_buffered_write_iomap_begin(
 	    !IS_ALIGNED(offset + count, mp->m_sb.sb_blocksize) ||
 	    (flags & IOMAP_ZERO)) {
 		error = xfs_zoned_fill_srcmap(ip, offset_fsb, &end_fsb, flags,
-				srcmap);
+				srcmap, iomap_flags);
 		if (error)
 			goto out_unlock;
 	}
@@ -1695,6 +1702,8 @@ xfs_zoned_buffered_write_iomap_begin(
 	if (!ip->i_cowfp)
 		xfs_ifork_init_cow(ip);
 
+	iomap_flags |= IOMAP_F_SHARED;
+
 	if (!xfs_iext_lookup_extent(ip, ip->i_cowfp, offset_fsb, &icur, &got))
 		got.br_startoff = end_fsb;
 	if (got.br_startoff <= offset_fsb) {
@@ -1826,9 +1835,12 @@ xfs_buffered_write_iomap_begin(
 	if (xfs_is_shutdown(mp))
 		return -EIO;
 
+	if (xfs_iflags_test(ip, XFS_VERITY_CONSTRUCTION))
+		iomap_flags |= IOMAP_F_FSVERITY;
+
 	if (xfs_is_zoned_inode(ip))
 		return xfs_zoned_buffered_write_iomap_begin(inode, offset,
-				count, flags, iomap, srcmap);
+				count, flags, iomap, srcmap, iomap_flags);
 
 	/* we can't use delayed allocations when using extent size hints */
 	if (xfs_get_extsz_hint(ip))
@@ -2112,7 +2124,8 @@ 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;
@@ -2216,12 +2229,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;
@@ -2235,8 +2253,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);
 }
 
 static DEFINE_IOMAP_ITER_NEXT(xfs_read_iomap_next, xfs_read_iomap_begin);
diff --git a/fs/xfs/xfs_iomap.h b/fs/xfs/xfs_iomap.h
index f2520a9b3a13..d3ca0f2afc9f 100644
--- a/fs/xfs/xfs_iomap.h
+++ b/fs/xfs/xfs_iomap.h
@@ -34,13 +34,14 @@ xfs_iomap_set_anon_write(
 	struct xfs_inode		*ip,
 	struct iomap			*iomap,
 	loff_t				offset,
-	loff_t				length)
+	loff_t				length,
+	u16				iomap_flags)
 {
 	iomap->type = IOMAP_MAPPED;
 	iomap->bdev = ip->i_mount->m_rtdev_targp->bt_bdev;
 	iomap->offset = offset;
 	iomap->length = length;
-	iomap->flags = IOMAP_F_ANON_WRITE | IOMAP_F_DIRTY;
+	iomap->flags = iomap_flags | IOMAP_F_ANON_WRITE | IOMAP_F_DIRTY;
 	if (bdev_has_integrity_csum(iomap->bdev))
 		iomap->flags |= IOMAP_F_INTEGRITY;
 }
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v18 06/15] xfs: use read ioend for fsverity data verification
  2026-11-02 14:41 [PATCH v18 00/15] fs-verity support for XFS with post EOF merkle tree Andrey Albershteyn
                   ` (4 preceding siblings ...)
  2026-11-02 14:41 ` [PATCH v18 05/15] xfs: handle fsverity I/O in write/read path Andrey Albershteyn
@ 2026-11-02 14:41 ` Andrey Albershteyn
  2026-11-03  9:39   ` Christoph Hellwig
  2026-11-02 14:41 ` [PATCH v18 07/15] xfs: add XFS_BMAPI_UNWRITTEN to unmap unwritten extents in __xfs_bunmapi() Andrey Albershteyn
                   ` (8 subsequent siblings)
  14 siblings, 1 reply; 31+ messages in thread
From: Andrey Albershteyn @ 2026-11-02 14:41 UTC (permalink / raw)
  To: ebiggers, hch, Carlos Maiolino, fsverity, linux-xfs
  Cc: Andrey Albershteyn, linux-fsdevel, david

Use read ioends for fsverity verification. Do not issue 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.

Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
---
 fs/xfs/Makefile       |  1 +
 fs/xfs/xfs_aops.c     | 12 ++++++----
 fs/xfs/xfs_file.c     |  3 ++-
 fs/xfs/xfs_fsverity.c | 46 +++++++++++++++++++++++++++++++++++++
 fs/xfs/xfs_fsverity.h | 40 ++++++++++++++++++++++++++++++++
 fs/xfs/xfs_ioend.c    | 53 ++++++++++++++++++++++++++++++++++++++-----
 fs/xfs/xfs_ioend.h    |  4 +++-
 fs/xfs/xfs_super.c    | 24 +++++++++++++++++++-
 8 files changed, 169 insertions(+), 14 deletions(-)
 create mode 100644 fs/xfs/xfs_fsverity.c
 create mode 100644 fs/xfs/xfs_fsverity.h

diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
index cb7f71457ee9..9edb2850f094 100644
--- a/fs/xfs/Makefile
+++ b/fs/xfs/Makefile
@@ -151,6 +151,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)
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
index 19640e4e3ed1..2f6e87991d83 100644
--- a/fs/xfs/xfs_aops.c
+++ b/fs/xfs/xfs_aops.c
@@ -611,7 +611,7 @@ xfs_bio_submit_read(
 {
 	xfs_ioend_submit_read(iter->inode, ctx->read_ctx,
 			ctx->read_ctx_file_offset,
-			iomap_ioend_flags(&iter->iomap));
+			iomap_ioend_flags(&iter->iomap), ctx->vi);
 	ctx->read_ctx = NULL;
 }
 
@@ -623,11 +623,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				pos)
 {
 	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, pos))
 		return &xfs_iomap_read_ops;
 	return &iomap_bio_read_ops;
 }
@@ -639,7 +641,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;
 }
@@ -650,7 +652,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);
 }
 
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index f0d000272521..dbb5f8f59678 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -224,7 +224,8 @@ xfs_dio_read_bounce_submit_io(
 	loff_t			file_offset)
 {
 	xfs_ioend_submit_read(iter->inode, bio, file_offset,
-			iomap_ioend_flags(&iter->iomap) | IOMAP_IOEND_DIRECT);
+			iomap_ioend_flags(&iter->iomap) | IOMAP_IOEND_DIRECT,
+			NULL);
 }
 
 static const struct iomap_dio_ops xfs_dio_read_bounce_ops = {
diff --git a/fs/xfs/xfs_fsverity.c b/fs/xfs/xfs_fsverity.c
new file mode 100644
index 000000000000..8fc3e763c017
--- /dev/null
+++ b/fs/xfs/xfs_fsverity.c
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2026 Red Hat, Inc.
+ */
+#include "xfs_platform.h"
+#include "xfs_fs.h"
+#include "xfs_shared.h"
+#include "xfs_format.h"
+#include "xfs_log_format.h"
+#include "xfs_trans_resv.h"
+#include "xfs_mount.h"
+#include "xfs_inode.h"
+#include "xfs_fsverity.h"
+#include <linux/fsverity.h>
+#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);
+}
+
+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);
+}
diff --git a/fs/xfs/xfs_fsverity.h b/fs/xfs/xfs_fsverity.h
new file mode 100644
index 000000000000..44f7bc7831f2
--- /dev/null
+++ b/fs/xfs/xfs_fsverity.h
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2026 Red Hat, Inc.
+ */
+#ifndef __XFS_FSVERITY_H__
+#define __XFS_FSVERITY_H__
+
+#include "xfs_platform.h"
+#include "xfs_verity.h"
+#include <linux/iomap.h>
+#include <linux/mempool.h>
+
+#ifdef CONFIG_FS_VERITY
+int xfs_fsverity_init(void);
+void xfs_fsverity_exit(void);
+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 bool xfs_fsverity_is_file_data(const struct xfs_inode *ip,
+					    loff_t offset)
+{
+	return false;
+}
+#endif	/* CONFIG_FS_VERITY */
+
+struct xfs_fsverity_ioend {
+	struct iomap_ioend	*ioend;
+	struct work_struct	work;
+};
+
+extern struct kmem_cache *xfs_fsverity_ioend_cache;
+extern mempool_t xfs_fsverity_ioend_pool;
+
+#endif	/* __XFS_FSVERITY_H__ */
diff --git a/fs/xfs/xfs_ioend.c b/fs/xfs/xfs_ioend.c
index 48becc3bf608..d30aee973a87 100644
--- a/fs/xfs/xfs_ioend.c
+++ b/fs/xfs/xfs_ioend.c
@@ -18,7 +18,26 @@
 #include "xfs_ioend.h"
 #include "xfs_error.h"
 #include "xfs_errortag.h"
+#include "xfs_fsverity.h"
 #include <linux/bio-integrity.h>
+#include <linux/fsverity.h>
+
+static void
+xfs_end_fsverity_io_read(
+	struct work_struct		*work)
+{
+	struct xfs_fsverity_ioend	*fsv_ioend =
+			container_of(work, struct xfs_fsverity_ioend, work);
+	struct iomap_ioend		*ioend = fsv_ioend->ioend;
+	struct bio			*bio = &ioend->io_bio;
+
+	mempool_free(fsv_ioend, &xfs_fsverity_ioend_pool);
+
+	if (!bio->bi_status)
+		fsverity_verify_bio(ioend->io_vi, bio);
+
+	iomap_finish_ioends(ioend, blk_status_to_errno(bio->bi_status));
+}
 
 static void
 xfs_dio_bounce_end_io(
@@ -93,12 +112,14 @@ xfs_read_bounce_and_resubmit(
 
 static void
 xfs_end_io_read(
-	struct bio		*bio)
+	struct bio			*bio)
 {
-	struct iomap_ioend	*ioend = iomap_ioend_from_bio(bio);
-	struct xfs_inode	*ip = XFS_I(ioend->io_inode);
-	struct xfs_mount	*mp = ip->i_mount;
-	int			error = blk_status_to_errno(bio->bi_status);
+	struct iomap_ioend		*ioend = iomap_ioend_from_bio(bio);
+	struct xfs_inode		*ip = XFS_I(ioend->io_inode);
+	struct xfs_mount		*mp = ip->i_mount;
+	int				error =
+			blk_status_to_errno(bio->bi_status);
+	struct xfs_fsverity_ioend	*fsv_ioend;
 
 	if (!error && (ioend->io_flags & IOMAP_IOEND_INTEGRITY)) {
 		error = iomap_ioend_integrity_verify(ioend);
@@ -117,6 +138,24 @@ xfs_end_io_read(
 		}
 	}
 
+	/*
+	 * 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)) {
+		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;
+	}
+
 	iomap_finish_ioends(ioend, error);
 }
 
@@ -125,13 +164,15 @@ xfs_ioend_submit_read(
 	struct inode		*inode,
 	struct bio		*bio,
 	loff_t			file_offset,
-	u16			ioend_flags)
+	u16			ioend_flags,
+	struct fsverity_info	*vi)
 {
 	struct xfs_inode	*ip = XFS_I(inode);
 	struct xfs_mount	*mp = ip->i_mount;
 	struct iomap_ioend	*ioend;
 
 	ioend = iomap_init_ioend(inode, bio, file_offset, ioend_flags);
+	ioend->io_vi = vi;
 	if ((ioend_flags & IOMAP_IOEND_DIRECT) &&
 	    READ_ONCE(mp->m_read_bounce) == XFS_READ_BOUNCE_ALWAYS) {
 		iomap_bounce_read(ioend, bdev_logical_block_size(bio->bi_bdev),
diff --git a/fs/xfs/xfs_ioend.h b/fs/xfs/xfs_ioend.h
index 7c2a1ea3e6ed..992c248a693a 100644
--- a/fs/xfs/xfs_ioend.h
+++ b/fs/xfs/xfs_ioend.h
@@ -2,6 +2,8 @@
 #ifndef __XFS_IOEND_H
 #define __XFS_IOEND_H
 
+#include <linux/fsverity.h>
+
 /*
  * Fast and loose check if this write could update the on-disk inode size.
  */
@@ -13,6 +15,6 @@ static inline bool xfs_ioend_is_append(struct iomap_ioend *ioend)
 
 void xfs_end_bio(struct bio *bio);
 void xfs_ioend_submit_read(struct inode *inode, struct bio *bio,
-		loff_t file_offset, u16 ioend_flags);
+		loff_t file_offset, u16 ioend_flags, struct fsverity_info *vi);
 
 #endif /* __XFS_IOEND_H */
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index 5a06132aa384..3a7d7334e9a6 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -2516,8 +2516,20 @@ xfs_init_caches(void)
 	if (!xfs_parent_args_cache)
 		goto out_destroy_xmi_cache;
 
+#ifdef CONFIG_FS_VERITY
+	xfs_fsverity_ioend_cache = kmem_cache_create("xfs_fsverity_ioend",
+					     sizeof(struct xfs_fsverity_ioend),
+					     0, 0, NULL);
+	if (!xfs_fsverity_ioend_cache)
+		goto out_destroy_parent_args_cache;
+#endif
+
 	return 0;
 
+#ifdef CONFIG_FS_VERITY
+ out_destroy_parent_args_cache:
+	kmem_cache_destroy(xfs_parent_args_cache);
+#endif
  out_destroy_xmi_cache:
 	kmem_cache_destroy(xfs_xmi_cache);
  out_destroy_xmd_cache:
@@ -2580,6 +2592,9 @@ xfs_destroy_caches(void)
 	 * destroy caches.
 	 */
 	rcu_barrier();
+#ifdef CONFIG_FS_VERITY
+	kmem_cache_destroy(xfs_fsverity_ioend_cache);
+#endif
 	kmem_cache_destroy(xfs_parent_args_cache);
 	kmem_cache_destroy(xfs_xmd_cache);
 	kmem_cache_destroy(xfs_xmi_cache);
@@ -2660,10 +2675,14 @@ 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;
@@ -2740,6 +2759,8 @@ 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:
@@ -2763,6 +2784,7 @@ exit_xfs_fs(void)
 	xfs_cleanup_procfs();
 	xfs_mru_cache_uninit();
 	xfs_destroy_workqueues();
+	xfs_fsverity_exit();
 	xfs_destroy_caches();
 	xfs_uuid_table_free();
 }
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v18 07/15] xfs: add XFS_BMAPI_UNWRITTEN to unmap unwritten extents in __xfs_bunmapi()
  2026-11-02 14:41 [PATCH v18 00/15] fs-verity support for XFS with post EOF merkle tree Andrey Albershteyn
                   ` (5 preceding siblings ...)
  2026-11-02 14:41 ` [PATCH v18 06/15] xfs: use read ioend for fsverity data verification Andrey Albershteyn
@ 2026-11-02 14:41 ` Andrey Albershteyn
  2026-11-03  9:41   ` Christoph Hellwig
  2026-11-02 14:41 ` [PATCH v18 08/15] xfs: don't remove written extents past EOF on fsverity inodes Andrey Albershteyn
                   ` (7 subsequent siblings)
  14 siblings, 1 reply; 31+ messages in thread
From: Andrey Albershteyn @ 2026-11-02 14:41 UTC (permalink / raw)
  To: ebiggers, hch, Carlos Maiolino, fsverity, linux-xfs
  Cc: Andrey Albershteyn, linux-fsdevel, david, Darrick J. Wong

The __xfs_bunmapi() is used to remove all extents past EOF. Add
XFS_BMAPI_UNWRITTEN to remove only unwritten extents, while leaving
written ones in place. This will be used in following patch to clean up
unwritten extents on fsverity inodes.

Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
---
 fs/xfs/libxfs/xfs_bmap.c | 6 +++++-
 fs/xfs/libxfs/xfs_bmap.h | 6 +++++-
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index a35a44cf8c63..706f2ead42f5 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -5279,6 +5279,10 @@ __xfs_bunmapi(
 		if (del.br_startoff + del.br_blockcount > end + 1)
 			del.br_blockcount = end + 1 - del.br_startoff;
 
+		if ((flags & XFS_BMAPI_UNWRITTEN) &&
+		    del.br_state != XFS_EXT_UNWRITTEN)
+			goto skip;
+
 		if (!isrt || (flags & XFS_BMAPI_REMAP))
 			goto delete;
 
@@ -5413,7 +5417,7 @@ __xfs_bunmapi(
 			if (error)
 				goto error0;
 		}
-
+skip:
 		end = del.br_startoff - 1;
 nodelete:
 		/*
diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h
index e9f5416e4c05..25b24ff8e4de 100644
--- a/fs/xfs/libxfs/xfs_bmap.h
+++ b/fs/xfs/libxfs/xfs_bmap.h
@@ -90,6 +90,9 @@ struct xfs_bmalloca {
 /* Try to align allocations to the extent size hint */
 #define XFS_BMAPI_EXTSZALIGN	(1u << 11)
 
+/* Process unwritten extents only. Used for unmapping */
+#define XFS_BMAPI_UNWRITTEN	(1u << 12)
+
 #define XFS_BMAPI_FLAGS \
 	{ XFS_BMAPI_ENTIRE,	"ENTIRE" }, \
 	{ XFS_BMAPI_METADATA,	"METADATA" }, \
@@ -102,7 +105,8 @@ struct xfs_bmalloca {
 	{ XFS_BMAPI_COWFORK,	"COWFORK" }, \
 	{ XFS_BMAPI_NODISCARD,	"NODISCARD" }, \
 	{ XFS_BMAPI_NORMAP,	"NORMAP" },\
-	{ XFS_BMAPI_EXTSZALIGN,	"EXTSZALIGN" }
+	{ XFS_BMAPI_EXTSZALIGN,	"EXTSZALIGN" }, \
+	{ XFS_BMAPI_UNWRITTEN,	"UNWRITTEN" }
 
 
 static inline int xfs_bmapi_aflag(int w)
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v18 08/15] xfs: don't remove written extents past EOF on fsverity inodes
  2026-11-02 14:41 [PATCH v18 00/15] fs-verity support for XFS with post EOF merkle tree Andrey Albershteyn
                   ` (6 preceding siblings ...)
  2026-11-02 14:41 ` [PATCH v18 07/15] xfs: add XFS_BMAPI_UNWRITTEN to unmap unwritten extents in __xfs_bunmapi() Andrey Albershteyn
@ 2026-11-02 14:41 ` Andrey Albershteyn
  2026-11-03  9:42   ` Christoph Hellwig
  2026-11-02 14:41 ` [PATCH v18 09/15] xfs: add fs-verity support Andrey Albershteyn
                   ` (6 subsequent siblings)
  14 siblings, 1 reply; 31+ messages in thread
From: Andrey Albershteyn @ 2026-11-02 14:41 UTC (permalink / raw)
  To: ebiggers, hch, Carlos Maiolino, fsverity, linux-xfs
  Cc: Andrey Albershteyn, linux-fsdevel, david, Darrick J. Wong

xfs_free_eofblocks() removes all extents past EOF unless the
XFS_DIFLAG_PREALLOC or XFS_DIFLAG_APPEND flags are set. This is
undesired for fsverity as it stores metadata beyond EOF. However, while
merkle tree is being built, delayed preallocation and unwritten extents
are used. After metadata construction is done, fsverity inodes becomes
read-only and won't be changed anymore, none of these unwritten extents
or preallocations in post EOF region will be used.

Let xfs_free_eofblocks() be called on fsverity inode as usual to remove
anything which is not written extent. However, inodes which are
undergoing merkle tree construction need to be skipped in case reclaim
takes place.

Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
---
 fs/xfs/xfs_bmap_util.c | 31 ++++++++++++++++++++++++++++---
 1 file changed, 28 insertions(+), 3 deletions(-)

diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
index 865aec3ae5ab..32cec523fd52 100644
--- a/fs/xfs/xfs_bmap_util.c
+++ b/fs/xfs/xfs_bmap_util.c
@@ -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,15 @@ xfs_can_free_eofblocks(
 	if (last_fsb <= end_fsb)
 		return false;
 
+	/*
+	 * 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 (fsverity_active(VFS_IC(ip)) ||
+	    xfs_iflags_test(ip, XFS_VERITY_CONSTRUCTION))
+		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
@@ -579,6 +589,9 @@ xfs_free_eofblocks(
 	struct xfs_trans	*tp;
 	struct xfs_mount	*mp = ip->i_mount;
 	int			error;
+	int			bmapi_flags = XFS_BMAPI_NODISCARD;
+	bool			has_verity =
+			ip->i_diflags2 & XFS_DIFLAG2_VERITY;
 
 	/* Attach the dquots to the inode up front. */
 	error = xfs_qm_dqattach(ip);
@@ -593,15 +606,20 @@ xfs_free_eofblocks(
 	 *
 	 * Note that this means we also leave speculative preallocations in
 	 * place for preallocated files.
+	 *
+	 * Clean up delalloc reservations for fsverity too as those won't be
+	 * used
 	 */
-	if (ip->i_diflags & (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)) {
+	if (ip->i_diflags & (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND) ||
+			has_verity) {
 		if (ip->i_delayed_blks) {
 			xfs_bmap_punch_delalloc_range(ip, XFS_DATA_FORK,
 				round_up(XFS_ISIZE(ip), mp->m_sb.sb_blocksize),
 				LLONG_MAX, NULL);
 		}
 		xfs_inode_clear_eofblocks_tag(ip);
-		return 0;
+		if (!has_verity)
+			return 0;
 	}
 
 	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp);
@@ -613,6 +631,13 @@ 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;
+
 	/*
 	 * Do not update the on-disk file size.  If we update the on-disk file
 	 * size and then the system crashes before the contents of the file are
@@ -620,7 +645,7 @@ xfs_free_eofblocks(
 	 * bug).
 	 */
 	error = xfs_itruncate_extents_flags(&tp, ip, XFS_DATA_FORK,
-				XFS_ISIZE(ip), XFS_BMAPI_NODISCARD);
+				XFS_ISIZE(ip), bmapi_flags);
 	if (error)
 		goto err_cancel;
 
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v18 09/15] xfs: add fs-verity support
  2026-11-02 14:41 [PATCH v18 00/15] fs-verity support for XFS with post EOF merkle tree Andrey Albershteyn
                   ` (7 preceding siblings ...)
  2026-11-02 14:41 ` [PATCH v18 08/15] xfs: don't remove written extents past EOF on fsverity inodes Andrey Albershteyn
@ 2026-11-02 14:41 ` Andrey Albershteyn
  2026-11-02 14:41 ` [PATCH v18 10/15] xfs: initialize fs-verity on file open Andrey Albershteyn
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 31+ messages in thread
From: Andrey Albershteyn @ 2026-11-02 14:41 UTC (permalink / raw)
  To: ebiggers, hch, Carlos Maiolino, fsverity, linux-xfs
  Cc: Andrey Albershteyn, linux-fsdevel, david

Add 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).

Pro-actively remove any unwritten extents as we use last extent to
locate descriptor.

Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 fs/xfs/xfs_fsverity.c | 425 +++++++++++++++++++++++++++++++++++++++++-
 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 +
 6 files changed, 440 insertions(+), 1 deletion(-)

diff --git a/fs/xfs/xfs_fsverity.c b/fs/xfs/xfs_fsverity.c
index 8fc3e763c017..441251b36073 100644
--- a/fs/xfs/xfs_fsverity.c
+++ b/fs/xfs/xfs_fsverity.c
@@ -6,13 +6,22 @@
 #include "xfs_fs.h"
 #include "xfs_shared.h"
 #include "xfs_format.h"
-#include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
 #include "xfs_inode.h"
+#include "xfs_log_format.h"
+#include "xfs_trans.h"
+#include "xfs_trace.h"
+#include "xfs_quota.h"
 #include "xfs_fsverity.h"
+#include "xfs_iomap.h"
+#include "xfs_error.h"
+#include "xfs_health.h"
+#include "xfs_bmap_util.h"
+#include "xfs_icache.h"
 #include <linux/fsverity.h>
 #include <linux/iomap.h>
+#include <linux/pagemap.h>
 
 struct kmem_cache *xfs_fsverity_ioend_cache;
 mempool_t xfs_fsverity_ioend_pool;
@@ -44,3 +53,417 @@ xfs_fsverity_is_file_data(
 	return fsverity_active(VFS_IC(ip)) &&
 			offset < xfs_fsverity_metadata_offset(ip);
 }
+
+/*
+ * Retrieve the verity descriptor.
+ */
+static int
+xfs_fsverity_get_descriptor(
+	struct inode		*inode,
+	void			*buf,
+	size_t			buf_size)
+{
+	struct xfs_inode	*ip = XFS_I(inode);
+	struct xfs_mount	*mp = ip->i_mount;
+	__be32			d_desc_size;
+	u32			desc_size;
+	u64			desc_size_pos;
+	int			error;
+	u64			desc_pos;
+	struct xfs_bmbt_irec	rec;
+	int			is_empty;
+	uint32_t		blocksize = i_blocksize(VFS_I(ip));
+	xfs_fileoff_t		last_block_offset;
+
+	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_EXCL);
+	if (error)
+		return error;
+
+	if (is_empty)
+		return -ENODATA;
+
+	last_block_offset =
+		XFS_FSB_TO_B(mp, rec.br_startoff + rec.br_blockcount);
+	if (last_block_offset <= xfs_fsverity_metadata_offset(ip))
+		return -ENODATA;
+
+	desc_size_pos = last_block_offset - sizeof(__be32);
+	error = fsverity_pagecache_read(inode, (char *)&d_desc_size,
+			sizeof(d_desc_size), desc_size_pos);
+	if (error)
+		return error;
+
+	desc_size = be32_to_cpu(d_desc_size);
+	if (XFS_IS_CORRUPT(mp, desc_size > FS_VERITY_MAX_DESCRIPTOR_SIZE))
+		return -ERANGE;
+	if (XFS_IS_CORRUPT(mp, desc_size > desc_size_pos))
+		return -ERANGE;
+
+	if (!buf_size)
+		return desc_size;
+
+	if (XFS_IS_CORRUPT(mp, desc_size > buf_size))
+		return -ERANGE;
+
+	desc_pos = round_down(desc_size_pos - desc_size, blocksize);
+	if (desc_pos < xfs_fsverity_metadata_offset(ip))
+		return -ERANGE;
+
+	error = fsverity_pagecache_read(inode, buf, desc_size, desc_pos);
+	if (error)
+		return error;
+
+	return desc_size;
+}
+
+static int
+xfs_fsverity_write_descriptor(
+	struct file		*file,
+	const void		*desc,
+	u32			desc_size,
+	u64			merkle_tree_size)
+{
+	int			error;
+	struct inode		*inode = file_inode(file);
+	struct xfs_inode	*ip = XFS_I(inode);
+	unsigned int		blksize = ip->i_mount->m_sb.sb_blocksize;
+	u64			tree_last_block =
+			xfs_fsverity_metadata_offset(ip) + merkle_tree_size;
+	u64			desc_pos =
+			round_up(tree_last_block, XFS_FSVERITY_START_ALIGN);
+	u64			desc_end = desc_pos + desc_size;
+	__be32			desc_size_disk = cpu_to_be32(desc_size);
+	u64			desc_size_pos =
+			round_up(desc_end + sizeof(desc_size_disk), blksize) -
+			sizeof(desc_size_disk);
+
+	error = iomap_fsverity_write(file, desc_size_pos, sizeof(__be32),
+			(const void *)&desc_size_disk,
+			&xfs_buffered_write_iomap_ops,
+			&xfs_iomap_write_ops);
+	if (error)
+		return error;
+
+	return iomap_fsverity_write(file, desc_pos, desc_size, desc,
+			&xfs_buffered_write_iomap_ops,
+			&xfs_iomap_write_ops);
+}
+
+/*
+ * Try to remove all the fsverity metadata after a failed enablement.
+ */
+static int
+xfs_fsverity_delete_metadata(
+	struct xfs_inode	*ip)
+{
+	struct xfs_trans	*tp;
+	struct xfs_mount	*mp = ip->i_mount;
+	int			error;
+
+	xfs_ilock(ip, XFS_MMAPLOCK_EXCL);
+	truncate_inode_pages(VFS_I(ip)->i_mapping, XFS_ISIZE(ip));
+
+	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp);
+	if (error) {
+		xfs_iunlock(ip, XFS_MMAPLOCK_EXCL);
+		return error;
+	}
+
+	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
+	 */
+	error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, XFS_ISIZE(ip));
+	if (error)
+		goto err_cancel;
+
+	error = xfs_trans_commit(tp);
+	xfs_iunlock(ip, XFS_MMAPLOCK_EXCL | XFS_ILOCK_EXCL);
+	return error;
+err_cancel:
+	xfs_trans_cancel(tp);
+	xfs_iunlock(ip, XFS_MMAPLOCK_EXCL | XFS_ILOCK_EXCL);
+	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.
+ */
+static int
+xfs_fsverity_begin_enable(
+	struct file		*filp)
+{
+	struct inode		*inode = file_inode(filp);
+	struct xfs_inode	*ip = XFS_I(inode);
+	int			error;
+
+	xfs_assert_ilocked(ip, XFS_IOLOCK_EXCL);
+
+	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;
+
+	/*
+	 * Flush pagecache before building Merkle tree. Inode is locked and no
+	 * further writes will happen to the file except fsverity metadata
+	 */
+	error = filemap_write_and_wait(inode->i_mapping);
+	if (error)
+		return error;
+
+	if (xfs_iflags_test_and_set(ip, XFS_VERITY_CONSTRUCTION))
+		return -EBUSY;
+
+	error = xfs_qm_dqattach(ip);
+	if (error)
+		goto out_clear;
+
+	error = xfs_fsverity_delete_metadata(ip);
+	if (error)
+		goto out_clear;
+	return error;
+out_clear:
+	xfs_iflags_clear(ip, XFS_VERITY_CONSTRUCTION);
+	return error;
+}
+
+/*
+ * Complete (or fail) the process of enabling fsverity.
+ */
+static int
+xfs_fsverity_end_enable(
+	struct file		*file,
+	const void		*desc,
+	size_t			desc_size,
+	u64			merkle_tree_size)
+{
+	struct inode		*inode = file_inode(file);
+	struct xfs_inode	*ip = XFS_I(inode);
+	struct xfs_mount	*mp = ip->i_mount;
+	struct xfs_trans	*tp;
+	int			error = 0;
+	loff_t			range_start = xfs_fsverity_metadata_offset(ip);
+
+	xfs_assert_ilocked(ip, XFS_IOLOCK_EXCL);
+
+	/* fs-verity failed, just cleanup */
+	if (desc == NULL)
+		goto out;
+
+	error = xfs_fsverity_write_descriptor(file, desc, desc_size,
+			merkle_tree_size);
+	if (error)
+		goto out;
+
+	/*
+	 * Wait for Merkle tree get written to disk before setting on-disk inode
+	 * flag and clearing XFS_VERITY_CONSTRUCTION
+	 */
+	error = filemap_write_and_wait_range(inode->i_mapping, range_start,
+			LLONG_MAX);
+	if (error)
+		goto out;
+
+	/*
+	 * Set fsverity inode flag
+	 */
+	error = xfs_trans_alloc_inode(ip, &M_RES(mp)->tr_ichange,
+			0, 0, false, &tp);
+	if (error)
+		goto out;
+
+	/*
+	 * Ensure that we've persisted the verity information before we enable
+	 * it on the inode and tell the caller we have sealed the inode.
+	 */
+	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);
+	if (error)
+		goto out;
+
+	inode_set_flags(inode, S_VERITY, S_VERITY);
+
+	/*
+	 * Proactively remove unwritten extents left by COW preallocations and
+	 * write preallocation in the merkle tree holes and past descriptor,
+	 * and any delayed preallocations
+	 */
+	error = xfs_free_eofblocks(ip);
+out:
+	if (error) {
+		int	error2;
+
+		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",
+					I_INO(ip), error2);
+	}
+
+	xfs_iflags_clear(ip, XFS_VERITY_CONSTRUCTION);
+	return error;
+}
+
+/*
+ * Retrieve a merkle tree block.
+ */
+static struct page *
+xfs_fsverity_read_merkle(
+	struct inode		*inode,
+	pgoff_t			index)
+{
+	index += xfs_fsverity_metadata_offset(XFS_I(inode)) >> PAGE_SHIFT;
+
+	return generic_read_merkle_tree_page(inode, index);
+}
+
+/*
+ * Retrieve a merkle tree block.
+ */
+static void
+xfs_fsverity_readahead_merkle_tree(
+	struct inode		*inode,
+	pgoff_t			index,
+	unsigned long		nr_pages)
+{
+	index += xfs_fsverity_metadata_offset(XFS_I(inode)) >> PAGE_SHIFT;
+
+	generic_readahead_merkle_tree(inode, index, nr_pages);
+}
+
+static inline bool
+xfs_fsverity_is_hashes_of_zeroed_blocks(
+	struct xfs_inode	*ip,
+	const void		*buf,
+	unsigned int		size,
+	const u8		*zero_digest,
+	unsigned int		digest_size)
+{
+	/*
+	 * If this is a block full of hashes of zeroed blocks, don't bother
+	 * storing the block. We can synthesize them later.
+	 *
+	 * However, do this only in case Merkle tree block == fs block size.
+	 * Iomap synthesizes these blocks based on holes in the merkle tree. We
+	 * won't be able to tell if something need to be synthesizes for the
+	 * range in the fs block. For example, for 4k filesystem block
+	 *
+	 *	[ 1k | zero hashes | zero hashes | 1k ]
+	 *
+	 * Iomap won't know about these empty blocks.
+	 */
+	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,
+			&xfs_buffered_write_iomap_ops,
+			&xfs_iomap_write_ops);
+}
+
+const struct fsverity_operations xfs_fsverity_ops = {
+	.begin_enable_verity		= xfs_fsverity_begin_enable,
+	.end_enable_verity		= xfs_fsverity_end_enable,
+	.get_verity_descriptor		= xfs_fsverity_get_descriptor,
+	.read_merkle_tree_page		= xfs_fsverity_read_merkle,
+	.readahead_merkle_tree		= xfs_fsverity_readahead_merkle_tree,
+	.write_merkle_tree_block	= xfs_fsverity_write_merkle,
+};
diff --git a/fs/xfs/xfs_fsverity.h b/fs/xfs/xfs_fsverity.h
index 44f7bc7831f2..43f8ef62e12a 100644
--- a/fs/xfs/xfs_fsverity.h
+++ b/fs/xfs/xfs_fsverity.h
@@ -8,9 +8,11 @@
 #include "xfs_platform.h"
 #include "xfs_verity.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);
 bool xfs_fsverity_is_file_data(const struct xfs_inode *ip, loff_t offset);
diff --git a/fs/xfs/xfs_message.c b/fs/xfs/xfs_message.c
index 0243e509a468..44b13d46049c 100644
--- a/fs/xfs/xfs_message.c
+++ b/fs/xfs/xfs_message.c
@@ -149,6 +149,10 @@ xfs_warn_experimental(
 			.opstate	= XFS_OPSTATE_WARNED_LARP,
 			.name		= "logged extended attributes",
 		},
+		[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);
diff --git a/fs/xfs/xfs_message.h b/fs/xfs/xfs_message.h
index 811b885f41c3..364fcc7e42b0 100644
--- a/fs/xfs/xfs_message.h
+++ b/fs/xfs/xfs_message.h
@@ -93,6 +93,7 @@ void xfs_buf_alert_ratelimited(struct xfs_buf *bp, const char *rlmsg,
 enum xfs_experimental_feat {
 	XFS_EXPERIMENTAL_SHRINK,
 	XFS_EXPERIMENTAL_LARP,
+	XFS_EXPERIMENTAL_FSVERITY,
 
 	XFS_EXPERIMENTAL_MAX,
 };
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index 700964048587..0b6463663599 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -599,6 +599,8 @@ __XFS_HAS_FEAT(nouuid, NOUUID)
 #define XFS_OPSTATE_RESUMING_QUOTAON	18
 /* (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) \
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index 3a7d7334e9a6..af679b6ab52b 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -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"
@@ -1736,6 +1737,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
@@ -1988,6 +1992,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;
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v18 10/15] xfs: initialize fs-verity on file open
  2026-11-02 14:41 [PATCH v18 00/15] fs-verity support for XFS with post EOF merkle tree Andrey Albershteyn
                   ` (8 preceding siblings ...)
  2026-11-02 14:41 ` [PATCH v18 09/15] xfs: add fs-verity support Andrey Albershteyn
@ 2026-11-02 14:41 ` Andrey Albershteyn
  2026-11-02 14:41 ` [PATCH v18 11/15] xfs: add fs-verity ioctls Andrey Albershteyn
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 31+ messages in thread
From: Andrey Albershteyn @ 2026-11-02 14:41 UTC (permalink / raw)
  To: ebiggers, hch, Carlos Maiolino, fsverity, linux-xfs
  Cc: Andrey Albershteyn, linux-fsdevel, david, Darrick J. Wong

fs-verity will read and attach metadata (not the tree itself) from
a disk for those inodes which already have fs-verity enabled.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
---
 fs/xfs/xfs_file.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index dbb5f8f59678..a610adc90c02 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -1793,11 +1793,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);
 }
 
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v18 11/15] xfs: add fs-verity ioctls
  2026-11-02 14:41 [PATCH v18 00/15] fs-verity support for XFS with post EOF merkle tree Andrey Albershteyn
                   ` (9 preceding siblings ...)
  2026-11-02 14:41 ` [PATCH v18 10/15] xfs: initialize fs-verity on file open Andrey Albershteyn
@ 2026-11-02 14:41 ` Andrey Albershteyn
  2026-11-02 14:41 ` [PATCH v18 12/15] xfs: advertise fs-verity being available on filesystem Andrey Albershteyn
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 31+ messages in thread
From: Andrey Albershteyn @ 2026-11-02 14:41 UTC (permalink / raw)
  To: ebiggers, hch, Carlos Maiolino, fsverity, linux-xfs
  Cc: Andrey Albershteyn, linux-fsdevel, david, Darrick J. Wong

Add fs-verity ioctls to enable, dump metadata (descriptor and Merkle
tree pages) and obtain file's digest.

[djwong: remove unnecessary casting]

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
---
 fs/xfs/xfs_ioctl.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index f81b6e52ac40..37c6a2fae58c 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -49,6 +49,7 @@
 
 #include <linux/mount.h>
 #include <linux/fileattr.h>
+#include <linux/fsverity.h>
 
 /* Return 0 on success or positive error */
 int
@@ -1575,6 +1576,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;
 	}
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v18 12/15] xfs: advertise fs-verity being available on filesystem
  2026-11-02 14:41 [PATCH v18 00/15] fs-verity support for XFS with post EOF merkle tree Andrey Albershteyn
                   ` (10 preceding siblings ...)
  2026-11-02 14:41 ` [PATCH v18 11/15] xfs: add fs-verity ioctls Andrey Albershteyn
@ 2026-11-02 14:41 ` Andrey Albershteyn
  2026-11-02 14:41 ` [PATCH v18 13/15] xfs: check and repair the verity inode flag state Andrey Albershteyn
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 31+ messages in thread
From: Andrey Albershteyn @ 2026-11-02 14:41 UTC (permalink / raw)
  To: ebiggers, hch, Carlos Maiolino, fsverity, linux-xfs
  Cc: Andrey Albershteyn, linux-fsdevel, david, Darrick J. Wong,
	Andrey Albershteyn

From: "Darrick J. Wong" <djwong@kernel.org>

Advertise that this filesystem supports fsverity.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Andrey Albershteyn <aalbersh@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
---
 fs/xfs/libxfs/xfs_fs.h | 1 +
 fs/xfs/libxfs/xfs_sb.c | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
index 185f09f327c0..c80133784419 100644
--- a/fs/xfs/libxfs/xfs_fs.h
+++ b/fs/xfs/libxfs/xfs_fs.h
@@ -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.
diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c
index 7629fc3f499f..3323b8dcc793 100644
--- a/fs/xfs/libxfs/xfs_sb.c
+++ b/fs/xfs/libxfs/xfs_sb.c
@@ -1546,6 +1546,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);
 
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v18 13/15] xfs: check and repair the verity inode flag state
  2026-11-02 14:41 [PATCH v18 00/15] fs-verity support for XFS with post EOF merkle tree Andrey Albershteyn
                   ` (11 preceding siblings ...)
  2026-11-02 14:41 ` [PATCH v18 12/15] xfs: advertise fs-verity being available on filesystem Andrey Albershteyn
@ 2026-11-02 14:41 ` Andrey Albershteyn
  2026-11-02 14:41 ` [PATCH v18 14/15] xfs: introduce health state for corrupted fsverity metadata Andrey Albershteyn
  2026-11-02 14:41 ` [PATCH v18 15/15] xfs: enable ro-compat fs-verity flag Andrey Albershteyn
  14 siblings, 0 replies; 31+ messages in thread
From: Andrey Albershteyn @ 2026-11-02 14:41 UTC (permalink / raw)
  To: ebiggers, hch, Carlos Maiolino, fsverity, linux-xfs
  Cc: Andrey Albershteyn, linux-fsdevel, david, Darrick J. Wong

From: "Darrick J. Wong" <djwong@kernel.org>

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.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 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 +++++++++++++++++++++++++
 4 files changed, 98 insertions(+)

diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
index cbfe5e6f779d..fb0ae227df54 100644
--- a/fs/xfs/scrub/common.c
+++ b/fs/xfs/scrub/common.c
@@ -45,6 +45,8 @@
 #include "scrub/health.h"
 #include "scrub/tempfile.h"
 
+#include <linux/fsverity.h>
+
 /* Common code for the metadata scrubbers. */
 
 /*
@@ -1765,3 +1767,54 @@ xchk_inode_count_blocks(
 	return xfs_bmap_count_blocks(sc->tp, sc->ip, whichfork, nextents,
 			count);
 }
+
+/*
+ * If this inode has S_VERITY set on it, read the verity info. If the reading
+ * fails with anything other than ENOMEM, the file is corrupt, which we can
+ * detect later with fsverity_active.
+ *
+ * Callers must hold the IOLOCK and must not hold the ILOCK of sc->ip because
+ * activation reads inode data.
+ */
+int
+xchk_inode_setup_verity(
+	struct xfs_scrub	*sc)
+{
+	int			error;
+
+	if (!fsverity_active(VFS_I(sc->ip)))
+		return 0;
+
+	error = fsverity_ensure_verity_info(VFS_I(sc->ip));
+	switch (error) {
+	case 0:
+		/* fsverity is active */
+		break;
+	case -ENODATA:
+	case -EMSGSIZE:
+	case -EFSCORRUPTED:
+	case -ERANGE:
+	case -EBADMSG:
+		/*
+		 * The nonzero errno codes above are the error codes that can
+		 * be returned from fsverity on metadata validation errors.
+		 */
+		return 0;
+	default:
+		/* runtime errors */
+		return error;
+	}
+
+	return 0;
+}
+
+/*
+ * Is this a verity file that failed to activate?  Callers must have tried to
+ * activate fsverity via xchk_inode_setup_verity.
+ */
+bool
+xchk_inode_verity_broken(
+	struct xfs_inode	*ip)
+{
+	return fsverity_active(VFS_I(ip)) && !fsverity_get_info(VFS_I(ip));
+}
diff --git a/fs/xfs/scrub/common.h b/fs/xfs/scrub/common.h
index 181028f0c655..b59d4792a805 100644
--- a/fs/xfs/scrub/common.h
+++ b/fs/xfs/scrub/common.h
@@ -261,6 +261,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);
diff --git a/fs/xfs/scrub/inode.c b/fs/xfs/scrub/inode.c
index bb8d2bc008e0..1d21758e0df0 100644
--- a/fs/xfs/scrub/inode.c
+++ b/fs/xfs/scrub/inode.c
@@ -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, I_INO(sc->ip));
 
+	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, I_INO(sc->ip), &di);
diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c
index a9ccf763c059..e84eaa8178dc 100644
--- a/fs/xfs/scrub/inode_repair.c
+++ b/fs/xfs/scrub/inode_repair.c
@@ -577,6 +577,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;
@@ -1659,6 +1661,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;
@@ -2198,6 +2204,27 @@ xrep_inode_reset_dquots(
 # define xrep_inode_reset_dquots(sc)		(0)
 #endif
 
+/*
+ * 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_set_flags(inode, 0, S_VERITY);
+
+		xfs_trans_log_inode(sc->tp, sc->ip, XFS_ILOG_CORE);
+	}
+
+	return 0;
+}
+
 /* Repair an inode's fields. */
 int
 xrep_inode(
@@ -2247,6 +2274,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)
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v18 14/15] xfs: introduce health state for corrupted fsverity metadata
  2026-11-02 14:41 [PATCH v18 00/15] fs-verity support for XFS with post EOF merkle tree Andrey Albershteyn
                   ` (12 preceding siblings ...)
  2026-11-02 14:41 ` [PATCH v18 13/15] xfs: check and repair the verity inode flag state Andrey Albershteyn
@ 2026-11-02 14:41 ` Andrey Albershteyn
  2026-11-02 14:41 ` [PATCH v18 15/15] xfs: enable ro-compat fs-verity flag Andrey Albershteyn
  14 siblings, 0 replies; 31+ messages in thread
From: Andrey Albershteyn @ 2026-11-02 14:41 UTC (permalink / raw)
  To: ebiggers, hch, Carlos Maiolino, fsverity, linux-xfs
  Cc: Andrey Albershteyn, linux-fsdevel, david, Darrick J. Wong

Report corrupted fsverity descriptor through health system.

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/libxfs/xfs_fs.h     |  1 +
 fs/xfs/libxfs/xfs_health.h |  4 +++-
 fs/xfs/xfs_fsverity.c      | 25 +++++++++++++++++++------
 fs/xfs/xfs_health.c        |  1 +
 4 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
index c80133784419..84d62b7506a9 100644
--- a/fs/xfs/libxfs/xfs_fs.h
+++ b/fs/xfs/libxfs/xfs_fs.h
@@ -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
diff --git a/fs/xfs/libxfs/xfs_health.h b/fs/xfs/libxfs/xfs_health.h
index 1d45cf5789e8..932b447190da 100644
--- a/fs/xfs/libxfs/xfs_health.h
+++ b/fs/xfs/libxfs/xfs_health.h
@@ -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 | \
diff --git a/fs/xfs/xfs_fsverity.c b/fs/xfs/xfs_fsverity.c
index 441251b36073..9b83a0735dc0 100644
--- a/fs/xfs/xfs_fsverity.c
+++ b/fs/xfs/xfs_fsverity.c
@@ -89,13 +89,17 @@ xfs_fsverity_get_descriptor(
 	if (error)
 		return error;
 
-	if (is_empty)
+	if (is_empty) {
+		xfs_inode_mark_sick(XFS_I(inode), XFS_SICK_INO_FSVERITY);
 		return -ENODATA;
+	}
 
 	last_block_offset =
 		XFS_FSB_TO_B(mp, rec.br_startoff + rec.br_blockcount);
-	if (last_block_offset <= xfs_fsverity_metadata_offset(ip))
+	if (last_block_offset <= xfs_fsverity_metadata_offset(ip)) {
+		xfs_inode_mark_sick(XFS_I(inode), XFS_SICK_INO_FSVERITY);
 		return -ENODATA;
+	}
 
 	desc_size_pos = last_block_offset - sizeof(__be32);
 	error = fsverity_pagecache_read(inode, (char *)&d_desc_size,
@@ -104,20 +108,29 @@ 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);
-	if (desc_pos < xfs_fsverity_metadata_offset(ip))
+	if (desc_pos < xfs_fsverity_metadata_offset(ip)) {
+		xfs_inode_mark_sick(XFS_I(inode), XFS_SICK_INO_FSVERITY);
 		return -ERANGE;
+	}
 
 	error = fsverity_pagecache_read(inode, buf, desc_size, desc_pos);
 	if (error)
diff --git a/fs/xfs/xfs_health.c b/fs/xfs/xfs_health.c
index 239b843e83d4..be66760fb120 100644
--- a/fs/xfs/xfs_health.c
+++ b/fs/xfs/xfs_health.c
@@ -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. */
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v18 15/15] xfs: enable ro-compat fs-verity flag
  2026-11-02 14:41 [PATCH v18 00/15] fs-verity support for XFS with post EOF merkle tree Andrey Albershteyn
                   ` (13 preceding siblings ...)
  2026-11-02 14:41 ` [PATCH v18 14/15] xfs: introduce health state for corrupted fsverity metadata Andrey Albershteyn
@ 2026-11-02 14:41 ` Andrey Albershteyn
  2026-11-03  9:44   ` Christoph Hellwig
  14 siblings, 1 reply; 31+ messages in thread
From: Andrey Albershteyn @ 2026-11-02 14:41 UTC (permalink / raw)
  To: ebiggers, hch, Carlos Maiolino, fsverity, linux-xfs
  Cc: Andrey Albershteyn, linux-fsdevel, david, Darrick J. Wong

Finalize fs-verity integration in XFS by making kernel fs-verity
aware with ro-compat flag.

Reviewed-by: Darrick J. Wong <djwong@kernel.org>
[djwong: add spaces]
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
---
 fs/xfs/libxfs/xfs_format.h | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index e1f50ad18f0b..6594fbe4f7f6 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -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_ALL
 static inline bool
 xfs_sb_has_ro_compat_feature(
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH v18 04/15] xfs: don't report dio_mem_align and dio_offset_align for fsverity files
  2026-11-02 14:41 ` [PATCH v18 04/15] xfs: don't report dio_mem_align and dio_offset_align for fsverity files Andrey Albershteyn
@ 2026-11-03  9:23   ` Christoph Hellwig
  0 siblings, 0 replies; 31+ messages in thread
From: Christoph Hellwig @ 2026-11-03  9:23 UTC (permalink / raw)
  To: Andrey Albershteyn
  Cc: ebiggers, hch, Carlos Maiolino, fsverity, linux-xfs,
	linux-fsdevel, david, Darrick J. Wong

On Mon, Nov 02, 2026 at 03:41:34PM +0100, Andrey Albershteyn wrote:
>  	struct block_device	*bdev = target->bt_bdev;
>  
>  	stat->result_mask |= STATX_DIOALIGN | STATX_DIO_READ_ALIGN;
> +
> +	if (fsverity_active(VFS_I(ip)))
> +		return;
> +

A comment based on the commit message on why filling out the comments
here is fine would probably be helpful.

Otherwise looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v18 05/15] xfs: handle fsverity I/O in write/read path
  2026-11-02 14:41 ` [PATCH v18 05/15] xfs: handle fsverity I/O in write/read path Andrey Albershteyn
@ 2026-11-03  9:37   ` Christoph Hellwig
  2026-11-03 13:55     ` Andrey Albershteyn
  0 siblings, 1 reply; 31+ messages in thread
From: Christoph Hellwig @ 2026-11-03  9:37 UTC (permalink / raw)
  To: Andrey Albershteyn
  Cc: ebiggers, hch, Carlos Maiolino, fsverity, linux-xfs,
	linux-fsdevel, david, Darrick J. Wong

On Mon, Nov 02, 2026 at 03:41:35PM +0100, Andrey Albershteyn wrote:
> @@ -41,6 +41,7 @@
>  #include "xfs_inode_util.h"
>  #include "xfs_rtgroup.h"
>  #include "xfs_zone_alloc.h"
> +#include "xfs_verity.h"

I think the Sashiko comment that this breaks the build until
xfs_fsverifty.h is added is spot on.  Easiest is probably to just add
the header in this patch already.

>  	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
> @@ -265,7 +270,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);

Is there a reason to not just move the IOMAP_F_FSVERITY handling
into xfs_bmbt_to_iomap?  It would break if single extent is shared
between data and verity data, but we already leave a large enough hole
that this could never happen, right?

If we need to protect agaist that explicitly passing the offset might
still be better, although it would be a bit ugly.

>  	xfs_iunlock(ip, XFS_ILOCK_EXCL);
>  
>  	xfs_iomap_set_anon_write(ip, &wpc->iomap, offset,
> -			XFS_FSB_TO_B(mp, count_fsb));
> +			XFS_FSB_TO_B(mp, count_fsb), iomap_flags);

Same for xfs_iomap_set_anon_write, although we already do have the
offset here in either case.

> +static int
> +xfs_iomap_writepages(
> +	struct xfs_inode		*ip,
> +	struct iomap_writepage_ctx	*ctx)
> +{
> +	/*
> +	 * 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))
> +		ctx->iomap.flags |= IOMAP_F_FSVERITY;

Sashiko complained about this, but I also really don't understand
how setting ctx->iomap.flags before we even get a mapping to start
with make much sense.  This should be set together with filling the
iomap either way.

> +#include "xfs_verity.h"
> +#include <linux/fsverity.h>
>  
>  #define XFS_ALLOC_ALIGN(mp, off) \
>  	(((off) >> mp->m_allocsize_log) << mp->m_allocsize_log)
> @@ -883,6 +885,9 @@ xfs_direct_write_iomap_begin(
>  	if (flags & IOMAP_ATOMIC)
>  		iomap_flags |= IOMAP_F_ATOMIC_BIO;
>  
> +	if (xfs_iflags_test(ip, XFS_VERITY_CONSTRUCTION))
> +		iomap_flags |= IOMAP_F_FSVERITY;
> +
>  	/*
>  	 * COW writes may allocate delalloc space or convert unwritten COW
>  	 * extents, so we need to make sure to take the lock exclusively here.
> @@ -1023,7 +1028,8 @@ 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);

Does passing on the other iomap_flags hurt here?  Filtering out a
specific one looks pretty odd.


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v18 06/15] xfs: use read ioend for fsverity data verification
  2026-11-02 14:41 ` [PATCH v18 06/15] xfs: use read ioend for fsverity data verification Andrey Albershteyn
@ 2026-11-03  9:39   ` Christoph Hellwig
  0 siblings, 0 replies; 31+ messages in thread
From: Christoph Hellwig @ 2026-11-03  9:39 UTC (permalink / raw)
  To: Andrey Albershteyn
  Cc: ebiggers, hch, Carlos Maiolino, fsverity, linux-xfs,
	linux-fsdevel, david

Looks good modulo the xfs_fsverity.h issue:

Reviewed-by: Christoph Hellwig <hch@lst.de>

On Mon, Nov 02, 2026 at 03:41:36PM +0100, Andrey Albershteyn wrote:
> Use read ioends for fsverity verification. Do not issue 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.
> 
> Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
> ---
>  fs/xfs/Makefile       |  1 +
>  fs/xfs/xfs_aops.c     | 12 ++++++----
>  fs/xfs/xfs_file.c     |  3 ++-
>  fs/xfs/xfs_fsverity.c | 46 +++++++++++++++++++++++++++++++++++++
>  fs/xfs/xfs_fsverity.h | 40 ++++++++++++++++++++++++++++++++
>  fs/xfs/xfs_ioend.c    | 53 ++++++++++++++++++++++++++++++++++++++-----
>  fs/xfs/xfs_ioend.h    |  4 +++-
>  fs/xfs/xfs_super.c    | 24 +++++++++++++++++++-
>  8 files changed, 169 insertions(+), 14 deletions(-)
>  create mode 100644 fs/xfs/xfs_fsverity.c
>  create mode 100644 fs/xfs/xfs_fsverity.h
> 
> diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
> index cb7f71457ee9..9edb2850f094 100644
> --- a/fs/xfs/Makefile
> +++ b/fs/xfs/Makefile
> @@ -151,6 +151,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)
> diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
> index 19640e4e3ed1..2f6e87991d83 100644
> --- a/fs/xfs/xfs_aops.c
> +++ b/fs/xfs/xfs_aops.c
> @@ -611,7 +611,7 @@ xfs_bio_submit_read(
>  {
>  	xfs_ioend_submit_read(iter->inode, ctx->read_ctx,
>  			ctx->read_ctx_file_offset,
> -			iomap_ioend_flags(&iter->iomap));
> +			iomap_ioend_flags(&iter->iomap), ctx->vi);
>  	ctx->read_ctx = NULL;
>  }
>  
> @@ -623,11 +623,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				pos)
>  {
>  	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, pos))
>  		return &xfs_iomap_read_ops;
>  	return &iomap_bio_read_ops;
>  }
> @@ -639,7 +641,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;
>  }
> @@ -650,7 +652,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);
>  }
>  
> diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
> index f0d000272521..dbb5f8f59678 100644
> --- a/fs/xfs/xfs_file.c
> +++ b/fs/xfs/xfs_file.c
> @@ -224,7 +224,8 @@ xfs_dio_read_bounce_submit_io(
>  	loff_t			file_offset)
>  {
>  	xfs_ioend_submit_read(iter->inode, bio, file_offset,
> -			iomap_ioend_flags(&iter->iomap) | IOMAP_IOEND_DIRECT);
> +			iomap_ioend_flags(&iter->iomap) | IOMAP_IOEND_DIRECT,
> +			NULL);
>  }
>  
>  static const struct iomap_dio_ops xfs_dio_read_bounce_ops = {
> diff --git a/fs/xfs/xfs_fsverity.c b/fs/xfs/xfs_fsverity.c
> new file mode 100644
> index 000000000000..8fc3e763c017
> --- /dev/null
> +++ b/fs/xfs/xfs_fsverity.c
> @@ -0,0 +1,46 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2026 Red Hat, Inc.
> + */
> +#include "xfs_platform.h"
> +#include "xfs_fs.h"
> +#include "xfs_shared.h"
> +#include "xfs_format.h"
> +#include "xfs_log_format.h"
> +#include "xfs_trans_resv.h"
> +#include "xfs_mount.h"
> +#include "xfs_inode.h"
> +#include "xfs_fsverity.h"
> +#include <linux/fsverity.h>
> +#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);
> +}
> +
> +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);
> +}
> diff --git a/fs/xfs/xfs_fsverity.h b/fs/xfs/xfs_fsverity.h
> new file mode 100644
> index 000000000000..44f7bc7831f2
> --- /dev/null
> +++ b/fs/xfs/xfs_fsverity.h
> @@ -0,0 +1,40 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2026 Red Hat, Inc.
> + */
> +#ifndef __XFS_FSVERITY_H__
> +#define __XFS_FSVERITY_H__
> +
> +#include "xfs_platform.h"
> +#include "xfs_verity.h"
> +#include <linux/iomap.h>
> +#include <linux/mempool.h>
> +
> +#ifdef CONFIG_FS_VERITY
> +int xfs_fsverity_init(void);
> +void xfs_fsverity_exit(void);
> +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 bool xfs_fsverity_is_file_data(const struct xfs_inode *ip,
> +					    loff_t offset)
> +{
> +	return false;
> +}
> +#endif	/* CONFIG_FS_VERITY */
> +
> +struct xfs_fsverity_ioend {
> +	struct iomap_ioend	*ioend;
> +	struct work_struct	work;
> +};
> +
> +extern struct kmem_cache *xfs_fsverity_ioend_cache;
> +extern mempool_t xfs_fsverity_ioend_pool;
> +
> +#endif	/* __XFS_FSVERITY_H__ */
> diff --git a/fs/xfs/xfs_ioend.c b/fs/xfs/xfs_ioend.c
> index 48becc3bf608..d30aee973a87 100644
> --- a/fs/xfs/xfs_ioend.c
> +++ b/fs/xfs/xfs_ioend.c
> @@ -18,7 +18,26 @@
>  #include "xfs_ioend.h"
>  #include "xfs_error.h"
>  #include "xfs_errortag.h"
> +#include "xfs_fsverity.h"
>  #include <linux/bio-integrity.h>
> +#include <linux/fsverity.h>
> +
> +static void
> +xfs_end_fsverity_io_read(
> +	struct work_struct		*work)
> +{
> +	struct xfs_fsverity_ioend	*fsv_ioend =
> +			container_of(work, struct xfs_fsverity_ioend, work);
> +	struct iomap_ioend		*ioend = fsv_ioend->ioend;
> +	struct bio			*bio = &ioend->io_bio;
> +
> +	mempool_free(fsv_ioend, &xfs_fsverity_ioend_pool);
> +
> +	if (!bio->bi_status)
> +		fsverity_verify_bio(ioend->io_vi, bio);
> +
> +	iomap_finish_ioends(ioend, blk_status_to_errno(bio->bi_status));
> +}
>  
>  static void
>  xfs_dio_bounce_end_io(
> @@ -93,12 +112,14 @@ xfs_read_bounce_and_resubmit(
>  
>  static void
>  xfs_end_io_read(
> -	struct bio		*bio)
> +	struct bio			*bio)
>  {
> -	struct iomap_ioend	*ioend = iomap_ioend_from_bio(bio);
> -	struct xfs_inode	*ip = XFS_I(ioend->io_inode);
> -	struct xfs_mount	*mp = ip->i_mount;
> -	int			error = blk_status_to_errno(bio->bi_status);
> +	struct iomap_ioend		*ioend = iomap_ioend_from_bio(bio);
> +	struct xfs_inode		*ip = XFS_I(ioend->io_inode);
> +	struct xfs_mount		*mp = ip->i_mount;
> +	int				error =
> +			blk_status_to_errno(bio->bi_status);
> +	struct xfs_fsverity_ioend	*fsv_ioend;
>  
>  	if (!error && (ioend->io_flags & IOMAP_IOEND_INTEGRITY)) {
>  		error = iomap_ioend_integrity_verify(ioend);
> @@ -117,6 +138,24 @@ xfs_end_io_read(
>  		}
>  	}
>  
> +	/*
> +	 * 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)) {
> +		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;
> +	}
> +
>  	iomap_finish_ioends(ioend, error);
>  }
>  
> @@ -125,13 +164,15 @@ xfs_ioend_submit_read(
>  	struct inode		*inode,
>  	struct bio		*bio,
>  	loff_t			file_offset,
> -	u16			ioend_flags)
> +	u16			ioend_flags,
> +	struct fsverity_info	*vi)
>  {
>  	struct xfs_inode	*ip = XFS_I(inode);
>  	struct xfs_mount	*mp = ip->i_mount;
>  	struct iomap_ioend	*ioend;
>  
>  	ioend = iomap_init_ioend(inode, bio, file_offset, ioend_flags);
> +	ioend->io_vi = vi;
>  	if ((ioend_flags & IOMAP_IOEND_DIRECT) &&
>  	    READ_ONCE(mp->m_read_bounce) == XFS_READ_BOUNCE_ALWAYS) {
>  		iomap_bounce_read(ioend, bdev_logical_block_size(bio->bi_bdev),
> diff --git a/fs/xfs/xfs_ioend.h b/fs/xfs/xfs_ioend.h
> index 7c2a1ea3e6ed..992c248a693a 100644
> --- a/fs/xfs/xfs_ioend.h
> +++ b/fs/xfs/xfs_ioend.h
> @@ -2,6 +2,8 @@
>  #ifndef __XFS_IOEND_H
>  #define __XFS_IOEND_H
>  
> +#include <linux/fsverity.h>
> +
>  /*
>   * Fast and loose check if this write could update the on-disk inode size.
>   */
> @@ -13,6 +15,6 @@ static inline bool xfs_ioend_is_append(struct iomap_ioend *ioend)
>  
>  void xfs_end_bio(struct bio *bio);
>  void xfs_ioend_submit_read(struct inode *inode, struct bio *bio,
> -		loff_t file_offset, u16 ioend_flags);
> +		loff_t file_offset, u16 ioend_flags, struct fsverity_info *vi);
>  
>  #endif /* __XFS_IOEND_H */
> diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
> index 5a06132aa384..3a7d7334e9a6 100644
> --- a/fs/xfs/xfs_super.c
> +++ b/fs/xfs/xfs_super.c
> @@ -2516,8 +2516,20 @@ xfs_init_caches(void)
>  	if (!xfs_parent_args_cache)
>  		goto out_destroy_xmi_cache;
>  
> +#ifdef CONFIG_FS_VERITY
> +	xfs_fsverity_ioend_cache = kmem_cache_create("xfs_fsverity_ioend",
> +					     sizeof(struct xfs_fsverity_ioend),
> +					     0, 0, NULL);
> +	if (!xfs_fsverity_ioend_cache)
> +		goto out_destroy_parent_args_cache;
> +#endif
> +
>  	return 0;
>  
> +#ifdef CONFIG_FS_VERITY
> + out_destroy_parent_args_cache:
> +	kmem_cache_destroy(xfs_parent_args_cache);
> +#endif
>   out_destroy_xmi_cache:
>  	kmem_cache_destroy(xfs_xmi_cache);
>   out_destroy_xmd_cache:
> @@ -2580,6 +2592,9 @@ xfs_destroy_caches(void)
>  	 * destroy caches.
>  	 */
>  	rcu_barrier();
> +#ifdef CONFIG_FS_VERITY
> +	kmem_cache_destroy(xfs_fsverity_ioend_cache);
> +#endif
>  	kmem_cache_destroy(xfs_parent_args_cache);
>  	kmem_cache_destroy(xfs_xmd_cache);
>  	kmem_cache_destroy(xfs_xmi_cache);
> @@ -2660,10 +2675,14 @@ 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;
> @@ -2740,6 +2759,8 @@ 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:
> @@ -2763,6 +2784,7 @@ exit_xfs_fs(void)
>  	xfs_cleanup_procfs();
>  	xfs_mru_cache_uninit();
>  	xfs_destroy_workqueues();
> +	xfs_fsverity_exit();
>  	xfs_destroy_caches();
>  	xfs_uuid_table_free();
>  }
> -- 
> 2.54.0
> 
> 
---end quoted text---

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v18 07/15] xfs: add XFS_BMAPI_UNWRITTEN to unmap unwritten extents in __xfs_bunmapi()
  2026-11-02 14:41 ` [PATCH v18 07/15] xfs: add XFS_BMAPI_UNWRITTEN to unmap unwritten extents in __xfs_bunmapi() Andrey Albershteyn
@ 2026-11-03  9:41   ` Christoph Hellwig
  2026-11-03 14:31     ` Andrey Albershteyn
  0 siblings, 1 reply; 31+ messages in thread
From: Christoph Hellwig @ 2026-11-03  9:41 UTC (permalink / raw)
  To: Andrey Albershteyn
  Cc: ebiggers, hch, Carlos Maiolino, fsverity, linux-xfs,
	linux-fsdevel, david, Darrick J. Wong

On Mon, Nov 02, 2026 at 03:41:37PM +0100, Andrey Albershteyn wrote:
> The __xfs_bunmapi() is used to remove all extents past EOF. Add
> XFS_BMAPI_UNWRITTEN to remove only unwritten extents, while leaving
> written ones in place. This will be used in following patch to clean up
> unwritten extents on fsverity inodes.

As discussed before, we either need to fix the Sashiko complains (which
could get really annoying), or disallow fsverity on RT files with
rt extent size > 1.  And probably also add a soft assert about this
to __xfs_bunmapi itself to make the limitations clear.

Otherwise this looks good.


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v18 08/15] xfs: don't remove written extents past EOF on fsverity inodes
  2026-11-02 14:41 ` [PATCH v18 08/15] xfs: don't remove written extents past EOF on fsverity inodes Andrey Albershteyn
@ 2026-11-03  9:42   ` Christoph Hellwig
  0 siblings, 0 replies; 31+ messages in thread
From: Christoph Hellwig @ 2026-11-03  9:42 UTC (permalink / raw)
  To: Andrey Albershteyn
  Cc: ebiggers, hch, Carlos Maiolino, fsverity, linux-xfs,
	linux-fsdevel, david, Darrick J. Wong

On Mon, Nov 02, 2026 at 03:41:38PM +0100, Andrey Albershteyn wrote:
> xfs_free_eofblocks() removes all extents past EOF unless the
> XFS_DIFLAG_PREALLOC or XFS_DIFLAG_APPEND flags are set. This is
> undesired for fsverity as it stores metadata beyond EOF. However, while
> merkle tree is being built, delayed preallocation and unwritten extents
> are used. After metadata construction is done, fsverity inodes becomes
> read-only and won't be changed anymore, none of these unwritten extents
> or preallocations in post EOF region will be used.
> 
> Let xfs_free_eofblocks() be called on fsverity inode as usual to remove
> anything which is not written extent. However, inodes which are
> undergoing merkle tree construction need to be skipped in case reclaim
> takes place.

The Sashiko comment about the enabled flag here looks correct to me,
or am I misisng something?


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v18 15/15] xfs: enable ro-compat fs-verity flag
  2026-11-02 14:41 ` [PATCH v18 15/15] xfs: enable ro-compat fs-verity flag Andrey Albershteyn
@ 2026-11-03  9:44   ` Christoph Hellwig
  0 siblings, 0 replies; 31+ messages in thread
From: Christoph Hellwig @ 2026-11-03  9:44 UTC (permalink / raw)
  To: Andrey Albershteyn
  Cc: ebiggers, hch, Carlos Maiolino, fsverity, linux-xfs,
	linux-fsdevel, david, Darrick J. Wong

Kinda skipped over a lot more of the Sashiko comments that look
at least remotely sensible to the one here, which seems most
important:  XFS_SB_FEAT_RO_COMPAT_VERITY for sure should not
be allowed if CONFIG_FS_VERITY is not set.


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v18 05/15] xfs: handle fsverity I/O in write/read path
  2026-11-03  9:37   ` Christoph Hellwig
@ 2026-11-03 13:55     ` Andrey Albershteyn
  2026-11-03 14:53       ` Christoph Hellwig
  0 siblings, 1 reply; 31+ messages in thread
From: Andrey Albershteyn @ 2026-11-03 13:55 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: ebiggers, hch, Carlos Maiolino, fsverity, linux-xfs,
	linux-fsdevel, david, Darrick J. Wong

On 2026-11-03 01:37:46, Christoph Hellwig wrote:
> On Mon, Nov 02, 2026 at 03:41:35PM +0100, Andrey Albershteyn wrote:
> > @@ -41,6 +41,7 @@
> >  #include "xfs_inode_util.h"
> >  #include "xfs_rtgroup.h"
> >  #include "xfs_zone_alloc.h"
> > +#include "xfs_verity.h"
> 
> I think the Sashiko comment that this breaks the build until
> xfs_fsverifty.h is added is spot on.  Easiest is probably to just add
> the header in this patch already.
> 
> >  	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
> > @@ -265,7 +270,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);
> 
> Is there a reason to not just move the IOMAP_F_FSVERITY handling
> into xfs_bmbt_to_iomap?  It would break if single extent is shared
> between data and verity data, but we already leave a large enough hole
> that this could never happen, right?

I think it can be moved to xfs_bmbt_to_iomap(), but we will need an
offset there. The one extent case could happen if file size is
exactly 64k and we got continuous phys space allocation with merkle
tree (then the extents will be merged).

> 
> If we need to protect agaist that explicitly passing the offset might
> still be better, although it would be a bit ugly.
> 
> >  	xfs_iunlock(ip, XFS_ILOCK_EXCL);
> >  
> >  	xfs_iomap_set_anon_write(ip, &wpc->iomap, offset,
> > -			XFS_FSB_TO_B(mp, count_fsb));
> > +			XFS_FSB_TO_B(mp, count_fsb), iomap_flags);
> 
> Same for xfs_iomap_set_anon_write, although we already do have the
> offset here in either case.
> 
> > +static int
> > +xfs_iomap_writepages(
> > +	struct xfs_inode		*ip,
> > +	struct iomap_writepage_ctx	*ctx)
> > +{
> > +	/*
> > +	 * 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))
> > +		ctx->iomap.flags |= IOMAP_F_FSVERITY;
> 
> Sashiko complained about this, but I also really don't understand
> how setting ctx->iomap.flags before we even get a mapping to start
> with make much sense.  This should be set together with filling the
> iomap either way.

The problem here is that when we found a dirty folio to writeback,
and we know it's beyond EOF, how to find out that's it's fsverity
folio. We don't have any fsverity metadata attach to an inode yet as
we are in the process of creating it.

This is not a nice workaround here, but I use stale iomap.flags
here. So, every next folio in that iomap has the stale flags from a
previous one, which has fsverity set. This should be fine as the
only folios written, at this point, are fsverity metadata.

Here I set it for the first folio in the iomap, to get it started.
Otherwise, writeback will just will not continue on folios post EOF.

This could be probably done by elevating "verity in construction"
into inode_state_flags *shrug*

> 
> > +#include "xfs_verity.h"
> > +#include <linux/fsverity.h>
> >  
> >  #define XFS_ALLOC_ALIGN(mp, off) \
> >  	(((off) >> mp->m_allocsize_log) << mp->m_allocsize_log)
> > @@ -883,6 +885,9 @@ xfs_direct_write_iomap_begin(
> >  	if (flags & IOMAP_ATOMIC)
> >  		iomap_flags |= IOMAP_F_ATOMIC_BIO;
> >  
> > +	if (xfs_iflags_test(ip, XFS_VERITY_CONSTRUCTION))
> > +		iomap_flags |= IOMAP_F_FSVERITY;
> > +
> >  	/*
> >  	 * COW writes may allocate delalloc space or convert unwritten COW
> >  	 * extents, so we need to make sure to take the lock exclusively here.
> > @@ -1023,7 +1028,8 @@ 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);
> 
> Does passing on the other iomap_flags hurt here?  Filtering out a
> specific one looks pretty odd.
> 

I suppose it's fine, the buffered-io path won't have anything except
fsverity, and direct-io can set IOMAP_F_DIRTY/IOMAP_F_ATOMIC_BIO
which is probably not desired for source cow extent. I will test it

-- 
- Andrey

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v18 07/15] xfs: add XFS_BMAPI_UNWRITTEN to unmap unwritten extents in __xfs_bunmapi()
  2026-11-03  9:41   ` Christoph Hellwig
@ 2026-11-03 14:31     ` Andrey Albershteyn
  2026-11-03 14:39       ` Christoph Hellwig
  0 siblings, 1 reply; 31+ messages in thread
From: Andrey Albershteyn @ 2026-11-03 14:31 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: ebiggers, hch, Carlos Maiolino, fsverity, linux-xfs,
	linux-fsdevel, david, Darrick J. Wong

On 2026-11-03 01:41:19, Christoph Hellwig wrote:
> On Mon, Nov 02, 2026 at 03:41:37PM +0100, Andrey Albershteyn wrote:
> > The __xfs_bunmapi() is used to remove all extents past EOF. Add
> > XFS_BMAPI_UNWRITTEN to remove only unwritten extents, while leaving
> > written ones in place. This will be used in following patch to clean up
> > unwritten extents on fsverity inodes.
> 
> As discussed before, we either need to fix the Sashiko complains (which
> could get really annoying), or disallow fsverity on RT files with
> rt extent size > 1.  And probably also add a soft assert about this
> to __xfs_bunmapi itself to make the limitations clear.
> 
> Otherwise this looks good.
> 

Yes, I added the check in "[PATCH v18 09/15] xfs: add fs-verity
support" [1] in xfs_fsverity_begin_enable()

+	/*
+	 * 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;

1: https://lore.kernel.org/linux-xfs/20261102144147.2393369-10-aalbersh@kernel.org/

-- 
- Andrey

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v18 07/15] xfs: add XFS_BMAPI_UNWRITTEN to unmap unwritten extents in __xfs_bunmapi()
  2026-11-03 14:31     ` Andrey Albershteyn
@ 2026-11-03 14:39       ` Christoph Hellwig
  2026-11-03 14:45         ` Andrey Albershteyn
  0 siblings, 1 reply; 31+ messages in thread
From: Christoph Hellwig @ 2026-11-03 14:39 UTC (permalink / raw)
  To: Andrey Albershteyn
  Cc: Christoph Hellwig, ebiggers, hch, Carlos Maiolino, fsverity,
	linux-xfs, linux-fsdevel, david, Darrick J. Wong

On Tue, Nov 03, 2026 at 03:31:15PM +0100, Andrey Albershteyn wrote:
> On 2026-11-03 01:41:19, Christoph Hellwig wrote:
> > On Mon, Nov 02, 2026 at 03:41:37PM +0100, Andrey Albershteyn wrote:
> > > The __xfs_bunmapi() is used to remove all extents past EOF. Add
> > > XFS_BMAPI_UNWRITTEN to remove only unwritten extents, while leaving
> > > written ones in place. This will be used in following patch to clean up
> > > unwritten extents on fsverity inodes.
> > 
> > As discussed before, we either need to fix the Sashiko complains (which
> > could get really annoying), or disallow fsverity on RT files with
> > rt extent size > 1.  And probably also add a soft assert about this
> > to __xfs_bunmapi itself to make the limitations clear.
> > 
> > Otherwise this looks good.
> > 
> 
> Yes, I added the check in "[PATCH v18 09/15] xfs: add fs-verity
> support" [1] in xfs_fsverity_begin_enable()
> 
> +	/*
> +	 * 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))

Please also add a similar check/comment in __xfs_bunampi for the
XFS_BMAPI_UNWRITTEN case as a safeguard and documentation of the
limitations.


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v18 07/15] xfs: add XFS_BMAPI_UNWRITTEN to unmap unwritten extents in __xfs_bunmapi()
  2026-11-03 14:39       ` Christoph Hellwig
@ 2026-11-03 14:45         ` Andrey Albershteyn
  2026-11-03 14:49           ` Christoph Hellwig
  0 siblings, 1 reply; 31+ messages in thread
From: Andrey Albershteyn @ 2026-11-03 14:45 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: ebiggers, hch, Carlos Maiolino, fsverity, linux-xfs,
	linux-fsdevel, david, Darrick J. Wong

On 2026-11-03 06:39:12, Christoph Hellwig wrote:
> On Tue, Nov 03, 2026 at 03:31:15PM +0100, Andrey Albershteyn wrote:
> > On 2026-11-03 01:41:19, Christoph Hellwig wrote:
> > > On Mon, Nov 02, 2026 at 03:41:37PM +0100, Andrey Albershteyn wrote:
> > > > The __xfs_bunmapi() is used to remove all extents past EOF. Add
> > > > XFS_BMAPI_UNWRITTEN to remove only unwritten extents, while leaving
> > > > written ones in place. This will be used in following patch to clean up
> > > > unwritten extents on fsverity inodes.
> > > 
> > > As discussed before, we either need to fix the Sashiko complains (which
> > > could get really annoying), or disallow fsverity on RT files with
> > > rt extent size > 1.  And probably also add a soft assert about this
> > > to __xfs_bunmapi itself to make the limitations clear.
> > > 
> > > Otherwise this looks good.
> > > 
> > 
> > Yes, I added the check in "[PATCH v18 09/15] xfs: add fs-verity
> > support" [1] in xfs_fsverity_begin_enable()
> > 
> > +	/*
> > +	 * 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))
> 
> Please also add a similar check/comment in __xfs_bunampi for the
> XFS_BMAPI_UNWRITTEN case as a safeguard and documentation of the
> limitations.
> 

Sure

I see that sashiko also noticed that realtime could be enabled
betwee _begin_enable() and _end_enable() as inode lock is not held
over that period. I will also add check there to forbid that, but
the xfs_dinode_verify() comment seems incorrect.

-- 
- Andrey

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v18 07/15] xfs: add XFS_BMAPI_UNWRITTEN to unmap unwritten extents in __xfs_bunmapi()
  2026-11-03 14:45         ` Andrey Albershteyn
@ 2026-11-03 14:49           ` Christoph Hellwig
  2026-11-03 15:17             ` Andrey Albershteyn
  0 siblings, 1 reply; 31+ messages in thread
From: Christoph Hellwig @ 2026-11-03 14:49 UTC (permalink / raw)
  To: Andrey Albershteyn
  Cc: Christoph Hellwig, ebiggers, hch, Carlos Maiolino, fsverity,
	linux-xfs, linux-fsdevel, david, Darrick J. Wong

On Tue, Nov 03, 2026 at 03:45:15PM +0100, Andrey Albershteyn wrote:
> 
> I see that sashiko also noticed that realtime could be enabled
> betwee _begin_enable() and _end_enable() as inode lock is not held
> over that period. I will also add check there to forbid that, but
> the xfs_dinode_verify() comment seems incorrect.

I don't think it's quite incorrect, although maybe a bit overzealous
given that we should not be reading an inode from disk that's not
been completed.  But adding a check there is cheap, so why not?


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v18 05/15] xfs: handle fsverity I/O in write/read path
  2026-11-03 13:55     ` Andrey Albershteyn
@ 2026-11-03 14:53       ` Christoph Hellwig
  2026-11-03 15:26         ` Andrey Albershteyn
  2026-11-03 22:03         ` Eric Biggers
  0 siblings, 2 replies; 31+ messages in thread
From: Christoph Hellwig @ 2026-11-03 14:53 UTC (permalink / raw)
  To: Andrey Albershteyn
  Cc: Christoph Hellwig, ebiggers, hch, Carlos Maiolino, fsverity,
	linux-xfs, linux-fsdevel, david, Darrick J. Wong

[Note: a question for Eric about lifting a flag to the VFS below]

On Tue, Nov 03, 2026 at 02:55:48PM +0100, Andrey Albershteyn wrote:
> > Is there a reason to not just move the IOMAP_F_FSVERITY handling
> > into xfs_bmbt_to_iomap?  It would break if single extent is shared
> > between data and verity data, but we already leave a large enough hole
> > that this could never happen, right?
> 
> I think it can be moved to xfs_bmbt_to_iomap(), but we will need an
> offset there. The one extent case could happen if file size is
> exactly 64k and we got continuous phys space allocation with merkle
> tree (then the extents will be merged).

Or a multiple of 64k, yeah.  I though we went for an "air gap",
but I have to admit I forgot all the details of this already.

I guess passing an offset it is then.  And maybe also add a comment
about that while you're at it?

> > Sashiko complained about this, but I also really don't understand
> > how setting ctx->iomap.flags before we even get a mapping to start
> > with make much sense.  This should be set together with filling the
> > iomap either way.
> 
> The problem here is that when we found a dirty folio to writeback,
> and we know it's beyond EOF, how to find out that's it's fsverity
> folio. We don't have any fsverity metadata attach to an inode yet as
> we are in the process of creating it.
> 
> This is not a nice workaround here, but I use stale iomap.flags
> here. So, every next folio in that iomap has the stale flags from a
> previous one, which has fsverity set. This should be fine as the
> only folios written, at this point, are fsverity metadata.
> 
> Here I set it for the first folio in the iomap, to get it started.
> Otherwise, writeback will just will not continue on folios post EOF.
> 
> This could be probably done by elevating "verity in construction"
> into inode_state_flags *shrug*

Lifting the flag to the VFS feels like a good and nicer than finding
backways communicaton channels through iomap.  And once we have more
file systems supporting fsverity a common flag vs one in each
file system might be worth it even without that.

Eric?


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v18 07/15] xfs: add XFS_BMAPI_UNWRITTEN to unmap unwritten extents in __xfs_bunmapi()
  2026-11-03 14:49           ` Christoph Hellwig
@ 2026-11-03 15:17             ` Andrey Albershteyn
  0 siblings, 0 replies; 31+ messages in thread
From: Andrey Albershteyn @ 2026-11-03 15:17 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: ebiggers, hch, Carlos Maiolino, fsverity, linux-xfs,
	linux-fsdevel, david, Darrick J. Wong

On 2026-11-03 06:49:30, Christoph Hellwig wrote:
> On Tue, Nov 03, 2026 at 03:45:15PM +0100, Andrey Albershteyn wrote:
> > 
> > I see that sashiko also noticed that realtime could be enabled
> > betwee _begin_enable() and _end_enable() as inode lock is not held
> > over that period. I will also add check there to forbid that, but
> > the xfs_dinode_verify() comment seems incorrect.
> 
> I don't think it's quite incorrect, although maybe a bit overzealous
> given that we should not be reading an inode from disk that's not
> been completed.  But adding a check there is cheap, so why not?
> 
> 

yeah, not incorrect just seem safe to leave it out. Even if both
flags happens to be set, the fsverity inodes will skip
xfs_free_eofblocks().

but sure it's cheap, I will add it

-- 
- Andrey

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v18 05/15] xfs: handle fsverity I/O in write/read path
  2026-11-03 14:53       ` Christoph Hellwig
@ 2026-11-03 15:26         ` Andrey Albershteyn
  2026-11-03 22:03         ` Eric Biggers
  1 sibling, 0 replies; 31+ messages in thread
From: Andrey Albershteyn @ 2026-11-03 15:26 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: ebiggers, hch, Carlos Maiolino, fsverity, linux-xfs,
	linux-fsdevel, david, Darrick J. Wong

On 2026-11-03 06:53:47, Christoph Hellwig wrote:
> [Note: a question for Eric about lifting a flag to the VFS below]
> 
> On Tue, Nov 03, 2026 at 02:55:48PM +0100, Andrey Albershteyn wrote:
> > > Is there a reason to not just move the IOMAP_F_FSVERITY handling
> > > into xfs_bmbt_to_iomap?  It would break if single extent is shared
> > > between data and verity data, but we already leave a large enough hole
> > > that this could never happen, right?
> > 
> > I think it can be moved to xfs_bmbt_to_iomap(), but we will need an
> > offset there. The one extent case could happen if file size is
> > exactly 64k and we got continuous phys space allocation with merkle
> > tree (then the extents will be merged).
> 
> Or a multiple of 64k, yeah.  I though we went for an "air gap",
> but I have to admit I forgot all the details of this already.
> 
> I guess passing an offset it is then.  And maybe also add a comment
> about that while you're at it?

air gap is zero on multiples of 64k, this is more of an alignment
with largest page size fsverity supports than the gap between
data/metadata (not to have mix of data/metadata in one page). The
xfs_fsverity_metadata_offset() is

	loff_t
	xfs_fsverity_metadata_offset(
		const struct xfs_inode	*ip)
	{
		return round_up(i_size_read(VFS_IC(ip)), XFS_FSVERITY_START_ALIGN);
	}

-- 
- Andrey

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v18 05/15] xfs: handle fsverity I/O in write/read path
  2026-11-03 14:53       ` Christoph Hellwig
  2026-11-03 15:26         ` Andrey Albershteyn
@ 2026-11-03 22:03         ` Eric Biggers
  1 sibling, 0 replies; 31+ messages in thread
From: Eric Biggers @ 2026-11-03 22:03 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Andrey Albershteyn, hch, Carlos Maiolino, fsverity, linux-xfs,
	linux-fsdevel, david, Darrick J. Wong

On Tue, Nov 03, 2026 at 06:53:47AM -0800, Christoph Hellwig wrote:
> > > Sashiko complained about this, but I also really don't understand
> > > how setting ctx->iomap.flags before we even get a mapping to start
> > > with make much sense.  This should be set together with filling the
> > > iomap either way.
> > 
> > The problem here is that when we found a dirty folio to writeback,
> > and we know it's beyond EOF, how to find out that's it's fsverity
> > folio. We don't have any fsverity metadata attach to an inode yet as
> > we are in the process of creating it.
> > 
> > This is not a nice workaround here, but I use stale iomap.flags
> > here. So, every next folio in that iomap has the stale flags from a
> > previous one, which has fsverity set. This should be fine as the
> > only folios written, at this point, are fsverity metadata.
> > 
> > Here I set it for the first folio in the iomap, to get it started.
> > Otherwise, writeback will just will not continue on folios post EOF.
> > 
> > This could be probably done by elevating "verity in construction"
> > into inode_state_flags *shrug*
> 
> Lifting the flag to the VFS feels like a good and nicer than finding
> backways communicaton channels through iomap.  And once we have more
> file systems supporting fsverity a common flag vs one in each
> file system might be worth it even without that.

I don't feel great about reserving space in 'struct inode' just for
temporary state of the FS_IOC_ENABLE_VERITY ioctl.  However, i_state is
currently using only 20 of its 32 available bits anyway, so it actually
would make no difference in the size and there are still plenty of bits
to go.  So sure, if adding I_VERITY_IN_PROGRESS makes things easier for
now, it sounds okay to me.

- Eric

^ permalink raw reply	[flat|nested] 31+ messages in thread

end of thread, other threads:[~2026-11-03 22:03 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-02 14:41 [PATCH v18 00/15] fs-verity support for XFS with post EOF merkle tree Andrey Albershteyn
2026-11-02 14:41 ` [PATCH v18 01/15] xfs: introduce fsverity on-disk changes Andrey Albershteyn
2026-11-02 14:41 ` [PATCH v18 02/15] xfs: don't allow to enable DAX on fs-verity sealed inode Andrey Albershteyn
2026-11-02 14:41 ` [PATCH v18 03/15] xfs: disable direct read path for fs-verity files Andrey Albershteyn
2026-11-02 14:41 ` [PATCH v18 04/15] xfs: don't report dio_mem_align and dio_offset_align for fsverity files Andrey Albershteyn
2026-11-03  9:23   ` Christoph Hellwig
2026-11-02 14:41 ` [PATCH v18 05/15] xfs: handle fsverity I/O in write/read path Andrey Albershteyn
2026-11-03  9:37   ` Christoph Hellwig
2026-11-03 13:55     ` Andrey Albershteyn
2026-11-03 14:53       ` Christoph Hellwig
2026-11-03 15:26         ` Andrey Albershteyn
2026-11-03 22:03         ` Eric Biggers
2026-11-02 14:41 ` [PATCH v18 06/15] xfs: use read ioend for fsverity data verification Andrey Albershteyn
2026-11-03  9:39   ` Christoph Hellwig
2026-11-02 14:41 ` [PATCH v18 07/15] xfs: add XFS_BMAPI_UNWRITTEN to unmap unwritten extents in __xfs_bunmapi() Andrey Albershteyn
2026-11-03  9:41   ` Christoph Hellwig
2026-11-03 14:31     ` Andrey Albershteyn
2026-11-03 14:39       ` Christoph Hellwig
2026-11-03 14:45         ` Andrey Albershteyn
2026-11-03 14:49           ` Christoph Hellwig
2026-11-03 15:17             ` Andrey Albershteyn
2026-11-02 14:41 ` [PATCH v18 08/15] xfs: don't remove written extents past EOF on fsverity inodes Andrey Albershteyn
2026-11-03  9:42   ` Christoph Hellwig
2026-11-02 14:41 ` [PATCH v18 09/15] xfs: add fs-verity support Andrey Albershteyn
2026-11-02 14:41 ` [PATCH v18 10/15] xfs: initialize fs-verity on file open Andrey Albershteyn
2026-11-02 14:41 ` [PATCH v18 11/15] xfs: add fs-verity ioctls Andrey Albershteyn
2026-11-02 14:41 ` [PATCH v18 12/15] xfs: advertise fs-verity being available on filesystem Andrey Albershteyn
2026-11-02 14:41 ` [PATCH v18 13/15] xfs: check and repair the verity inode flag state Andrey Albershteyn
2026-11-02 14:41 ` [PATCH v18 14/15] xfs: introduce health state for corrupted fsverity metadata Andrey Albershteyn
2026-11-02 14:41 ` [PATCH v18 15/15] xfs: enable ro-compat fs-verity flag Andrey Albershteyn
2026-11-03  9:44   ` Christoph Hellwig

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox