[f2fs-dev] [PATCH v15 18/25] xfs: make xfs_free_eofblocks() work with fsverity inodes
Andrey Albershteyn via Linux-f2fs-devel <[email protected]> Fri, 14 Aug 2026 11:24:35 +0200
| Newsgroups | net.sourceforge.lists.linux-f2fs-devel,dev.linux.lists.fsverity,org.kernel.vger.linux-block,org.kernel.vger.linux-btrfs,org.kernel.vger.linux-ext4,org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-unionfs,org.kernel.vger.linux-xfs |
|---|---|
| Message-ID | <[email protected]> |
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. 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. Signed-off-by: Andrey Albershteyn <[email protected]> --- fs/xfs/libxfs/xfs_bmap.c | 55 +++++++++++++++++++++++++++++----------- fs/xfs/libxfs/xfs_bmap.h | 6 ++++- fs/xfs/xfs_bmap_util.c | 25 +++++++++++++++--- 3 files changed, 67 insertions(+), 19 deletions(-) diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index cc48f6e20e80..a2d9cef952c4 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -6144,15 +6144,12 @@ 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( @@ -6162,23 +6159,51 @@ 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; diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h index d5f2729305fa..0f36431d9936 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) diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c index c88b9ade7389..36ac18df5743 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,13 @@ xfs_can_free_eofblocks( if (last_fsb <= end_fsb) return false; + /* + * Don't clean fsverity inodes which have merkle tree being built, the + * merkle tree is written beyond EOF + */ + if (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 +587,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 +604,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 +629,9 @@ xfs_free_eofblocks( xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, 0); + 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 +639,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 _______________________________________________ Linux-f2fs-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel