[PATCH v16 00/21] fs-verity support for XFS with post EOF merkle tree

Andrey Albershteyn <[email protected]>
Newsgroups org.kernel.vger.linux-fsdevel,dev.linux.lists.fsverity,net.sourceforge.lists.linux-f2fs-devel,org.kernel.vger.linux-btrfs,org.kernel.vger.linux-ext4,org.kernel.vger.linux-unionfs,org.kernel.vger.linux-xfs
Message-ID <[email protected]>
Hi all,

This is next revision of fsverity for XFS.

The main change from v15 is addion of kmem cache
xfs_fsverity_ioend_cache instead of adding work_struct to iomap's ioend
struct.

Patches without review:
[PATCH v16 12/21] xfs: use read ioend for fsverity data verification
[PATCH v16 13/21] xfs: add XFS_BMAPI_UNWRITTEN to unmap unwritten
[PATCH v16 14/21] xfs: don't remove written extents past EOF on

This series based on block/for-next (has lazy-bounce series)

block/for-next:
https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux.git/log/?h=for-next

kernel:
https://git.kernel.org/pub/scm/linux/kernel/git/aalbersh/xfs-linux.git/log/?h=fsverity

xfsprogs:
https://git.kernel.org/pub/scm/linux/kernel/git/aalbersh/xfsprogs-dev.git/log/?h=fsverity

xfstests:
https://git.kernel.org/pub/scm/linux/kernel/git/aalbersh/xfstests-dev.git/log/?h=fsverity

v15:
https://lore.kernel.org/fsverity/[email protected]/T/#t

v14:
https://lore.kernel.org/fsverity/[email protected]/T/#t

v13:
https://lore.kernel.org/fsverity/[email protected]/T/#t

v12:
https://lore.kernel.org/fsverity/[email protected]/T/#t

v11:
https://lore.kernel.org/all/[email protected]/

v10:
https://lore.kernel.org/fsverity/[email protected]/#r

v9:
https://lore.kernel.org/fsverity/[email protected]/#r

To: [email protected]
To: [email protected]
To: [email protected]
To: Carlos Maiolino <[email protected]>

Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]

Cc: [email protected]

---
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/[email protected]/T/#t
Changes in v3:
- Different on-disk and pagecache offset
- Use read path ioends
- Switch to hashtable fsverity info
- Synthesize merkle tree blocks full of zeroes
- Other minor refactors
- Link to v2: https://lore.kernel.org/fsverity/20260114164210.GO15583@frogsfrogsfrogs/T/#t
Changes in v2:
- Move to VFS interface for merkle tree block reading
- Drop patchset for per filesystem workqueues
- Change how offsets of the descriptor and tree metadata is calculated
- Store fs-verity descriptor in data fork side by side with merkle tree
- Simplify iomap changes, remove interface for post eof read/write
- Get rid of extended attribute implementation
- Link to v1: https://lore.kernel.org/r/[email protected]

Andrey Albershteyn (19):
  fsverity: report validation errors through fserror to fsnotify
  fsverity: expose ensure_fsverity_info()
  fsverity: pass digest size and hash of the all-zeroes block to ->write
  fsverity: hoist pagecache_read from f2fs/ext4 to fsverity
  fsverity: don't allow setting DAX file attribute on fsverity files
  fsverity: hoist statx reporting of fs-verity flag
  xfs: introduce fsverity on-disk changes
  xfs: don't allow to enable DAX on fs-verity sealed inode
  xfs: disable direct read path for fs-verity files
  xfs: don't report dio_mem_align and dio_offset_align for fsverity
    files
  xfs: handle fsverity I/O in write/read path
  xfs: use read ioend for fsverity data verification
  xfs: add XFS_BMAPI_UNWRITTEN to unmap unwritten extents in
    __xfs_bunmapi()
  xfs: don't remove written extents past EOF on fsverity inodes
  xfs: add fs-verity support
  xfs: initialize fs-verity on file open
  xfs: add fs-verity ioctls
  xfs: introduce health state for corrupted fsverity metadata
  xfs: enable ro-compat fs-verity flag

Darrick J. Wong (2):
  xfs: advertise fs-verity being available on filesystem
  xfs: check and repair the verity inode flag state

 fs/btrfs/inode.c               |   3 -
 fs/btrfs/verity.c              |   6 +-
 fs/ext4/inode.c                |   5 +-
 fs/ext4/verity.c               |  36 +--
 fs/f2fs/file.c                 |   5 +-
 fs/f2fs/verity.c               |  34 +--
 fs/file_attr.c                 |  11 +-
 fs/stat.c                      |   6 +-
 fs/verity/enable.c             |   4 +-
 fs/verity/open.c               |  26 ++-
 fs/verity/pagecache.c          |  33 +++
 fs/verity/verify.c             |   4 +
 fs/xfs/Makefile                |   1 +
 fs/xfs/libxfs/xfs_bmap.c       |  17 +-
 fs/xfs/libxfs/xfs_bmap.h       |   6 +-
 fs/xfs/libxfs/xfs_format.h     |  35 ++-
 fs/xfs/libxfs/xfs_fs.h         |   2 +
 fs/xfs/libxfs/xfs_health.h     |   4 +-
 fs/xfs/libxfs/xfs_inode_buf.c  |   8 +
 fs/xfs/libxfs/xfs_inode_util.c |   5 +-
 fs/xfs/libxfs/xfs_sb.c         |   4 +
 fs/xfs/scrub/common.c          |  55 +++++
 fs/xfs/scrub/common.h          |   2 +
 fs/xfs/scrub/inode.c           |   7 +
 fs/xfs/scrub/inode_repair.c    |  36 +++
 fs/xfs/xfs_aops.c              |  49 +++-
 fs/xfs/xfs_bmap_util.c         |  25 +-
 fs/xfs/xfs_file.c              |  71 ++++--
 fs/xfs/xfs_fsverity.c          | 407 +++++++++++++++++++++++++++++++++
 fs/xfs/xfs_fsverity.h          |  36 +++
 fs/xfs/xfs_health.c            |   1 +
 fs/xfs/xfs_inode.h             |   6 +
 fs/xfs/xfs_ioctl.c             |  14 ++
 fs/xfs/xfs_ioend.c             |  65 +++++-
 fs/xfs/xfs_ioend.h             |   4 +-
 fs/xfs/xfs_iomap.c             |  31 ++-
 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             |  22 ++
 include/linux/fsverity.h       |  10 +-
 43 files changed, 984 insertions(+), 138 deletions(-)
 create mode 100644 fs/xfs/xfs_fsverity.c
 create mode 100644 fs/xfs/xfs_fsverity.h

Range-diff against v15:
 1:  1aec2e239aff =  1:  094627f6c973 fsverity: report validation errors through fserror to fsnotify
 2:  eb9775389956 =  2:  877456f91be2 fsverity: expose ensure_fsverity_info()
 3:  62bc33559c3f =  3:  1ab385e28833 fsverity: pass digest size and hash of the all-zeroes block to ->write
 4:  5d4f63be1694 =  4:  d984a8f7ac2a fsverity: hoist pagecache_read from f2fs/ext4 to fsverity
 5:  4c9bfc9694f6 =  5:  bc529e4308a2 fsverity: don't allow setting DAX file attribute on fsverity files
 6:  4a0f5a07d0b1 =  6:  11b7b6d6b237 fsverity: hoist statx reporting of fs-verity flag
 7:  1695341b674c <  -:  ------------ block: add task-context bio completion infrastructure
 8:  43f924f152af <  -:  ------------ block: don't delay bio task completions
 9:  ab8ed572ce79 <  -:  ------------ iomap: add a iomap_ioend_flags helper
10:  3477d06ae82e <  -:  ------------ iomap: add a IOMAP_IOEND_INTEGRITY flag
12:  d96ffea67314 =  7:  f94348c524e8 xfs: introduce fsverity on-disk changes
13:  d8da1e4acec1 =  8:  6c459e4ba14a xfs: don't allow to enable DAX on fs-verity sealed inode
14:  f2125f58f0d5 !  9:  61dbf3277865 xfs: disable direct read path for fs-verity files
    @@ Commit message
     
      ## fs/xfs/xfs_file.c ##
     @@
    - #include <linux/fadvise.h>
      #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;
    @@ fs/xfs/xfs_file.c: xfs_file_dio_read(
     +		return xfs_file_buffered_read(iocb, to);
     +	}
      	if (mapping_stable_writes(iocb->ki_filp->f_mapping)) {
    - 		dio_ops = &xfs_dio_read_bounce_ops;
    - 		dio_flags |= IOMAP_DIO_BOUNCE;
    + 		ret = iomap_dio_rw(iocb, to, &xfs_read_iomap_ops,
    + 				&xfs_dio_read_bounce_ops, 0, NULL, 0);
     @@ fs/xfs/xfs_file.c: xfs_file_dax_read(
      	struct kiocb		*iocb,
      	struct iov_iter		*to)
15:  a30ca3efd40a ! 10:  a915e649b7b5 xfs: don't report dio_mem_align and dio_offset_align for fsverity files
    @@ Commit message
     
         Signed-off-by: Andrey Albershteyn <[email protected]>
         Acked-by: Eric Biggers <[email protected]>
    +    Reviewed-by: "Darrick J. Wong" <[email protected]>
     
      ## fs/xfs/xfs_iops.c ##
     @@
16:  0d9385f44edb ! 11:  9920843a040c xfs: handle fsverity I/O in write/read path
    @@ Commit message
         the inode.
     
         Signed-off-by: Andrey Albershteyn <[email protected]>
    +    Reviewed-by: "Darrick J. Wong" <[email protected]>
    +    Reviewed-by: Christoph Hellwig <[email protected]>
     
      ## fs/xfs/Makefile ##
     @@ fs/xfs/Makefile: xfs-$(CONFIG_XFS_POSIX_ACL)	+= xfs_acl.o
    @@ fs/xfs/xfs_aops.c
      #include "xfs_zone_alloc.h"
      #include "xfs_rtgroup.h"
     +#include "xfs_fsverity.h"
    - #include <linux/bio-integrity.h>
      
      struct xfs_writepage_ctx {
    + 	struct iomap_writepage_ctx ctx;
     @@ fs/xfs/xfs_aops.c: xfs_map_blocks(
      	int			retries = 0;
      	int			error = 0;
    @@ fs/xfs/xfs_aops.c: xfs_vm_writepages(
     
      ## fs/xfs/xfs_fsverity.c (new) ##
     @@
    -+/* SPDX-License-Identifier: GPL-2.0 */
    ++// SPDX-License-Identifier: GPL-2.0
     +/*
     + * Copyright (C) 2026 Red Hat, Inc.
     + */
    @@ fs/xfs/xfs_fsverity.c (new)
     
      ## fs/xfs/xfs_fsverity.h (new) ##
     @@
    -+/* SPDX-License-Identifier: GPL-2.0 */
    ++// SPDX-License-Identifier: GPL-2.0
     +/*
     + * Copyright (C) 2026 Red Hat, Inc.
     + */
    @@ fs/xfs/xfs_iomap.c: xfs_read_iomap_begin(
     +	return xfs_bmbt_to_iomap(ip, iomap, &imap, flags, iomap_flags, seq);
      }
      
    - const struct iomap_ops xfs_read_iomap_ops = {
    + static DEFINE_IOMAP_ITER_NEXT(xfs_read_iomap_next, xfs_read_iomap_begin);
     
      ## fs/xfs/xfs_iomap.h ##
     @@ fs/xfs/xfs_iomap.h: xfs_iomap_set_anon_write(
    @@ fs/xfs/xfs_iomap.h: xfs_iomap_set_anon_write(
      	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;
      }
    - 
    - static inline xfs_filblks_t
17:  ee12fec4a28e ! 12:  7bb9559cd4cb xfs: use read ioend for fsverity data verification
    @@ Commit message
         data that needs verification.
     
         Signed-off-by: Andrey Albershteyn <[email protected]>
    -    Reviewed-by: "Darrick J. Wong" <[email protected]>
     
      ## fs/xfs/xfs_aops.c ##
     @@
    + #include "xfs_zone_alloc.h"
      #include "xfs_rtgroup.h"
      #include "xfs_fsverity.h"
    - #include <linux/bio-integrity.h>
     +#include <linux/fsverity.h>
      
      struct xfs_writepage_ctx {
    @@ fs/xfs/xfs_aops.c: static const struct iomap_read_ops xfs_iomap_read_ops = {
      xfs_get_iomap_read_ops(
     -	const struct address_space	*mapping)
     +	const struct address_space	*mapping,
    -+	loff_t				position)
    ++	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, position))
    ++	    xfs_fsverity_is_file_data(ip, pos))
      		return &xfs_iomap_read_ops;
      	return &iomap_bio_read_ops;
      }
    @@ 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: xfs_fsverity_metadata_offset(
    +@@
    + #include <linux/fsverity.h>
    + #include <linux/iomap.h>
    + 
    ++struct kmem_cache *xfs_fsverity_ioend_cache;
    ++
    + 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.c: xfs_fsverity_metadata_offset(
     
      ## fs/xfs/xfs_fsverity.h ##
     @@
    + #define __XFS_FSVERITY_H__
    + 
    + #include "xfs_platform.h"
    ++#include <linux/iomap.h>
      
      #ifdef CONFIG_FS_VERITY
      loff_t xfs_fsverity_metadata_offset(const struct xfs_inode *ip);
    @@ fs/xfs/xfs_fsverity.h
     +}
      #endif	/* CONFIG_FS_VERITY */
      
    ++struct xfs_fsverity_ioend {
    ++	struct iomap_ioend	*ioend;
    ++	struct work_struct	work;
    ++};
    ++
    ++extern struct kmem_cache *xfs_fsverity_ioend_cache;
    ++
      #endif	/* __XFS_FSVERITY_H__ */
     
      ## fs/xfs/xfs_ioend.c ##
     @@
    - #include "xfs_reflink.h"
    - #include "xfs_zone_alloc.h"
      #include "xfs_ioend.h"
    -+#include "xfs_error.h"
    -+#include "xfs_errortag.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 work_struct		*work)
     +{
    -+	struct iomap_ioend	*ioend =
    -+		container_of(work, struct iomap_ioend, io_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;
     +
    -+	if (!ioend->io_bio.bi_status)
    -+		fsverity_verify_bio(ioend->io_vi, &ioend->io_bio);
    ++	kmem_cache_free(xfs_fsverity_ioend_cache, fsv_ioend);
     +
    -+	iomap_finish_ioends(
    -+		ioend, blk_status_to_errno(ioend->io_bio.bi_status));
    ++	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(
    +@@ fs/xfs/xfs_ioend.c: xfs_read_bounce_and_resubmit(
    + 
      static void
      xfs_end_io_read(
    - 	struct bio		*bio)
    +-	struct bio		*bio)
    ++	struct bio			*bio)
      {
    - 	struct iomap_ioend	*ioend = iomap_ioend_from_bio(bio);
    -+	struct xfs_inode	*ip = XFS_I(ioend->io_inode);
    - 	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 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);
    +@@ fs/xfs/xfs_ioend.c: xfs_end_io_read(
    + 		}
    + 	}
      
     +	/*
     +	 * If we have fsverity and block device integrity attached to this bio,
    @@ fs/xfs/xfs_ioend.c
     +	if (IS_ENABLED(CONFIG_FS_VERITY) && !error && ioend->io_vi &&
     +			xfs_fsverity_is_file_data(ip, ioend->io_offset)) {
     +		if (ioend->io_flags & IOMAP_IOEND_INTEGRITY) {
    -+			fsverity_enqueue_verify_work(&ioend->io_work);
    ++			fsv_ioend = kmem_cache_zalloc(xfs_fsverity_ioend_cache,
    ++					GFP_KERNEL);
    ++			if (!fsv_ioend) {
    ++				iomap_finish_ioends(ioend, -ENOMEM);
    ++				return;
    ++			}
    ++			fsv_ioend->ioend = ioend;
    ++			INIT_WORK(&fsv_ioend->work, xfs_end_fsverity_io_read);
    ++
    ++			fsverity_enqueue_verify_work(&fsv_ioend->work);
     +			return;
     +		}
     +
    @@ fs/xfs/xfs_ioend.c: xfs_ioend_submit_read(
     +	u16			ioend_flags,
     +	struct fsverity_info	*vi)
      {
    --	iomap_init_ioend(inode, bio, file_offset, ioend_flags);
    -+	struct iomap_ioend	*ioend;
    -+
    -+	ioend = iomap_init_ioend(inode, bio, file_offset, ioend_flags);
    + 	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;
    -+	INIT_WORK(&ioend->io_work, xfs_end_fsverity_io_read);
    -+
    - 	if (ioend_flags & IOMAP_IOEND_INTEGRITY)
    - 		fs_bio_integrity_alloc(bio);
    - 	bio->bi_end_io = xfs_end_io_read;
    + 	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),
     
      ## fs/xfs/xfs_ioend.h ##
     @@
    @@ fs/xfs/xfs_ioend.h: static inline bool xfs_ioend_is_append(struct iomap_ioend *i
      
      #endif /* __XFS_IOEND_H */
     
    - ## include/linux/iomap.h ##
    -@@ include/linux/iomap.h: struct iomap_ioend {
    - 	sector_t		io_sector;	/* start sector of ioend */
    - 	void			*io_private;	/* file system private data */
    - 	struct fsverity_info	*io_vi;		/* fsverity info */
    -+	struct work_struct	io_work;	/* fsverity blocking I/O */
    - 	struct bio		io_bio;		/* MUST BE LAST! */
    - };
    + ## fs/xfs/xfs_super.c ##
    +@@ fs/xfs/xfs_super.c: 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_fsverity_ioend_cache;
    ++#endif
    ++
    + 	return 0;
    + 
    ++#ifdef CONFIG_FS_VERITY
    ++ out_destroy_fsverity_ioend_cache:
    ++	kmem_cache_destroy(xfs_fsverity_ioend_cache);
    ++#endif
    +  out_destroy_xmi_cache:
    + 	kmem_cache_destroy(xfs_xmi_cache);
    +  out_destroy_xmd_cache:
    +@@ fs/xfs/xfs_super.c: 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);
11:  881f5c8f286f ! 13:  37c092fa5240 xfs: use BIO_COMPLETE_IN_TASK for bounce buffered read I/Os
    @@
      ## Metadata ##
    -Author: Christoph Hellwig <[email protected]>
    +Author: Andrey Albershteyn <[email protected]>
     
      ## Commit message ##
    -    xfs: use BIO_COMPLETE_IN_TASK for bounce buffered read I/Os
    +    xfs: add XFS_BMAPI_UNWRITTEN to unmap unwritten extents in __xfs_bunmapi()
     
    -    Stop using the xfs per-inode work struct for completing read bios, as
    -    unlike writes we don't want to serialize reads on a single inode as
    -    there is no exclusive resource contention for them.
    +    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.
     
    -    Factor the code for kicking off a read that needs and ioend and the
    -    task context completion into a single helper so that it is split off
    -    the xfs_end_bio machinery, which is not only used for writes.
    +    Signed-off-by: Andrey Albershteyn <[email protected]>
     
    -    Signed-off-by: Christoph Hellwig <[email protected]>
    -    Reviewed-by: "Darrick J. Wong" <[email protected]>
    -
    - ## fs/xfs/xfs_aops.c ##
    -@@ fs/xfs/xfs_aops.c: xfs_bio_submit_read(
    - 	const struct iomap_iter		*iter,
    - 	struct iomap_read_folio_ctx	*ctx)
    - {
    --	struct bio			*bio = ctx->read_ctx;
    + ## fs/xfs/libxfs/xfs_bmap.c ##
    +@@ fs/xfs/libxfs/xfs_bmap.c: __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;
    + 
    +@@ fs/xfs/libxfs/xfs_bmap.c: __xfs_bunmapi(
    + 			if (error)
    + 				goto error0;
    + 		}
     -
    --	/* defer read completions to the ioend workqueue */
    --	iomap_init_ioend(iter->inode, bio, ctx->read_ctx_file_offset,
    --		iomap_ioend_flags(&iter->iomap));
    --	iomap_bio_submit_read_endio(iter, ctx, xfs_end_bio);
    -+	xfs_ioend_submit_read(iter->inode, ctx->read_ctx,
    -+			ctx->read_ctx_file_offset,
    -+			iomap_ioend_flags(&iter->iomap));
    -+	ctx->read_ctx = NULL;
    - }
    - 
    - static const struct iomap_read_ops xfs_iomap_read_ops = {
    ++skip:
    + 		end = del.br_startoff - 1;
    + nodelete:
    + 		/*
     
    - ## fs/xfs/xfs_file.c ##
    -@@ fs/xfs/xfs_file.c: xfs_dio_read_bounce_submit_io(
    - 	struct bio		*bio,
    - 	loff_t			file_offset)
    - {
    --	iomap_init_ioend(iter->inode, bio, file_offset,
    --		iomap_ioend_flags(&iter->iomap) | IOMAP_IOEND_DIRECT);
    --	bio->bi_end_io = xfs_end_bio;
    --	submit_bio(bio);
    -+	xfs_ioend_submit_read(iter->inode, bio, file_offset,
    -+			iomap_ioend_flags(&iter->iomap) | IOMAP_IOEND_DIRECT);
    - }
    + ## fs/xfs/libxfs/xfs_bmap.h ##
    +@@ fs/xfs/libxfs/xfs_bmap.h: struct xfs_bmalloca {
    + /* Try to align allocations to the extent size hint */
    + #define XFS_BMAPI_EXTSZALIGN	(1u << 11)
      
    - static const struct iomap_dio_ops xfs_dio_read_bounce_ops = {
    -
    - ## fs/xfs/xfs_ioend.c ##
    -@@
    - #include "xfs_reflink.h"
    - #include "xfs_zone_alloc.h"
    - #include "xfs_ioend.h"
    -+#include <linux/bio-integrity.h>
    -+
    -+static void
    -+xfs_end_io_read(
    -+	struct bio		*bio)
    -+{
    -+	struct iomap_ioend	*ioend = iomap_ioend_from_bio(bio);
    -+	int			error = blk_status_to_errno(bio->bi_status);
    ++/* Process unwritten extents only. Used for unmapping */
    ++#define XFS_BMAPI_UNWRITTEN	(1u << 12)
     +
    -+	iomap_finish_ioends(ioend, error);
    -+}
    -+
    -+void
    -+xfs_ioend_submit_read(
    -+	struct inode		*inode,
    -+	struct bio		*bio,
    -+	loff_t			file_offset,
    -+	u16			ioend_flags)
    -+{
    -+	iomap_init_ioend(inode, bio, file_offset, ioend_flags);
    -+	if (ioend_flags & IOMAP_IOEND_INTEGRITY)
    -+		fs_bio_integrity_alloc(bio);
    -+	bio->bi_end_io = xfs_end_io_read;
    -+	bio_set_flag(bio, BIO_COMPLETE_IN_TASK);
    -+	submit_bio(bio);
    -+}
    - 
    - static void
    - xfs_ioend_put_open_zones(
    -@@ fs/xfs/xfs_ioend.c: xfs_end_io(
    - 			io_list))) {
    - 		list_del_init(&ioend->io_list);
    - 		iomap_ioend_try_merge(ioend, &tmp);
    --		if (bio_op(&ioend->io_bio) == REQ_OP_READ)
    --			iomap_finish_ioends(ioend,
    --				blk_status_to_errno(ioend->io_bio.bi_status));
    --		else
    --			xfs_end_ioend_write(ioend);
    -+		xfs_end_ioend_write(ioend);
    - 		cond_resched();
    - 	}
    - }
    -
    - ## fs/xfs/xfs_ioend.h ##
    -@@ fs/xfs/xfs_ioend.h: static inline bool xfs_ioend_is_append(struct iomap_ioend *ioend)
    - }
    + #define XFS_BMAPI_FLAGS \
    + 	{ XFS_BMAPI_ENTIRE,	"ENTIRE" }, \
    + 	{ XFS_BMAPI_METADATA,	"METADATA" }, \
    +@@ fs/xfs/libxfs/xfs_bmap.h: 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" }
      
    - 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);
      
    - #endif /* __XFS_IOEND_H */
    + static inline int xfs_bmapi_aflag(int w)
18:  d9a489488c05 ! 14:  2560cea141e6 xfs: make xfs_free_eofblocks() work with fsverity inodes
    @@ Metadata
     Author: Andrey Albershteyn <[email protected]>
     
      ## Commit message ##
    -    xfs: make xfs_free_eofblocks() work with fsverity inodes
    +    xfs: don't remove written extents past EOF on fsverity inodes
     
    -    xfs_free_eofblocks() removes any preallocations and unwritten extents
    -    beyond EOF. 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.
    +    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.
     
    -    Add XFS_BMAPI_UNWRITTEN and change xfs_bunmapi_range to remove only
    -    unwritten extents sitting beyond EOF and set it for fsverity inodes.
    -
    -    The xfs_free_eofblocks() will be called on fsverity inode as usual.
    -    However, inodes which are undergoing merkle tree construction need to
    -    be skipped in case reclaim takes place.
    +    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 <[email protected]>
     
    - ## fs/xfs/libxfs/xfs_bmap.c ##
    -@@ fs/xfs/libxfs/xfs_bmap.c: xfs_bmap_validate_extent(
    - 			XFS_IS_REALTIME_INODE(ip), whichfork, irec);
    - }
    - 
    --/*
    -- * Used in xfs_itruncate_extents().  This is the maximum number of extents
    -- * freed from a file in a single transaction.
    -- */
    --#define	XFS_ITRUNC_MAX_EXTENTS	2
    --
    - /*
    -  * Unmap every extent in part of an inode's fork.  We don't do any higher level
    -  * invalidation work at all.
    -+ *
    -+ * The XFS_BMAPI_UNWRITTEN could be passed to remove only unwritten extents,
    -+ * leaving out normal extents in place.
    -  */
    - int
    - xfs_bunmapi_range(
    -@@ fs/xfs/libxfs/xfs_bmap.c: xfs_bunmapi_range(
    - 	xfs_fileoff_t		startoff,
    - 	xfs_fileoff_t		endoff)
    - {
    --	xfs_filblks_t		unmap_len = endoff - startoff + 1;
    -+	xfs_filblks_t           unmap_len;
    - 	int			error = 0;
    -+	int			nimaps = 1;
    -+	int			done = 0;
    -+	struct xfs_bmbt_irec	imap;
    -+	int			read_flags =
    -+			flags & (XFS_BMAPI_ATTRFORK | XFS_BMAPI_ENTIRE);
    - 
    - 	xfs_assert_ilocked(ip, XFS_ILOCK_EXCL);
    - 
    --	while (unmap_len > 0) {
    --		ASSERT((*tpp)->t_highest_agno == NULLAGNUMBER);
    --		error = __xfs_bunmapi(*tpp, ip, startoff, &unmap_len, flags,
    --				XFS_ITRUNC_MAX_EXTENTS);
    -+	while (startoff < endoff) {
    -+		nimaps = 1;
    -+
    -+		error = xfs_bmapi_read(ip, startoff, endoff - startoff + 1,
    -+				&imap, &nimaps, read_flags);
    - 		if (error)
    - 			goto out;
    - 
    --		/* free the just unmapped extents */
    --		error = xfs_defer_finish(tpp);
    --		if (error)
    -+		if (nimaps == 0)
    - 			goto out;
    --		cond_resched();
    -+
    -+		if ((flags & XFS_BMAPI_UNWRITTEN) &&
    -+				imap.br_state != XFS_EXT_UNWRITTEN) {
    -+			startoff = imap.br_startoff + imap.br_blockcount;
    -+			continue;
    -+		}
    -+
    -+		unmap_len = min(endoff - imap.br_startoff + 1,
    -+				imap.br_blockcount);
    -+		done = 0;
    -+		while (!done) {
    -+			ASSERT((*tpp)->t_highest_agno == NULLAGNUMBER);
    -+			error = xfs_bunmapi(*tpp, ip, imap.br_startoff,
    -+					unmap_len, flags, nimaps, &done);
    -+			if (error)
    -+				goto out;
    -+
    -+			/* free the just unmapped extent */
    -+			error = xfs_defer_finish(tpp);
    -+			if (error)
    -+				goto out;
    -+			cond_resched();
    -+		}
    -+
    -+		startoff = imap.br_startoff + unmap_len;
    - 	}
    - out:
    - 	return error;
    -
    - ## fs/xfs/libxfs/xfs_bmap.h ##
    -@@ fs/xfs/libxfs/xfs_bmap.h: 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" }, \
    -@@ fs/xfs/libxfs/xfs_bmap.h: 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)
    -
      ## fs/xfs/xfs_bmap_util.c ##
     @@
      #include "xfs_rtbitmap.h"
19:  6b085a40ae6f ! 15:  7bb438e1a24e xfs: add fs-verity support
    @@ fs/xfs/xfs_fsverity.c
      #include <linux/iomap.h>
     +#include <linux/pagemap.h>
      
    - loff_t
    - xfs_fsverity_metadata_offset(
    + struct kmem_cache *xfs_fsverity_ioend_cache;
    + 
     @@ fs/xfs/xfs_fsverity.c: xfs_fsverity_is_file_data(
      	return fsverity_active(VFS_IC(ip)) &&
      			offset < xfs_fsverity_metadata_offset(ip);
    @@ fs/xfs/xfs_fsverity.c: xfs_fsverity_is_file_data(
     
      ## fs/xfs/xfs_fsverity.h ##
     @@
    - #define __XFS_FSVERITY_H__
      
      #include "xfs_platform.h"
    + #include <linux/iomap.h>
     +#include <linux/fsverity.h>
      
      #ifdef CONFIG_FS_VERITY
20:  f5d3e63d22d2 = 16:  6df81706af9b xfs: initialize fs-verity on file open
21:  736650f67ab2 = 17:  055d2c228fcf xfs: add fs-verity ioctls
22:  1a1f26614e69 = 18:  1f93d36e9a35 xfs: advertise fs-verity being available on filesystem
23:  58573cc99930 = 19:  c8496df7ca01 xfs: check and repair the verity inode flag state
24:  a69dadffffe7 = 20:  6009a2eb9a39 xfs: introduce health state for corrupted fsverity metadata
25:  be7cfc3ab7c3 = 21:  ae0ee66fb13a xfs: enable ro-compat fs-verity flag
-- 
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.