1
0

Merge tag 'xfs-fixes-6.18-rc5' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux

Pull xfs fixes from Carlos Maiolino:
 "This contain fixes for the RT and zoned allocator, and a few fixes for
  atomic writes"

* tag 'xfs-fixes-6.18-rc5' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux:
  xfs: free xfs_busy_extents structure when no RT extents are queued
  xfs: fix zone selection in xfs_select_open_zone_mru
  xfs: fix a rtgroup leak when xfs_init_zone fails
  xfs: fix various problems in xfs_atomic_write_cow_iomap_begin
  xfs: fix delalloc write failures in software-provided atomic writes
This commit is contained in:
Linus Torvalds
2025-11-08 08:43:01 -08:00
3 changed files with 76 additions and 16 deletions

View File

@@ -726,8 +726,10 @@ xfs_trim_rtgroup_extents(
break;
}
if (!tr.queued)
if (!tr.queued) {
kfree(tr.extents);
break;
}
/*
* We hand the extent list to the discard function here so the

View File

@@ -1091,6 +1091,29 @@ const struct iomap_ops xfs_zoned_direct_write_iomap_ops = {
};
#endif /* CONFIG_XFS_RT */
#ifdef DEBUG
static void
xfs_check_atomic_cow_conversion(
struct xfs_inode *ip,
xfs_fileoff_t offset_fsb,
xfs_filblks_t count_fsb,
const struct xfs_bmbt_irec *cmap)
{
struct xfs_iext_cursor icur;
struct xfs_bmbt_irec cmap2 = { };
if (xfs_iext_lookup_extent(ip, ip->i_cowfp, offset_fsb, &icur, &cmap2))
xfs_trim_extent(&cmap2, offset_fsb, count_fsb);
ASSERT(cmap2.br_startoff == cmap->br_startoff);
ASSERT(cmap2.br_blockcount == cmap->br_blockcount);
ASSERT(cmap2.br_startblock == cmap->br_startblock);
ASSERT(cmap2.br_state == cmap->br_state);
}
#else
# define xfs_check_atomic_cow_conversion(...) ((void)0)
#endif
static int
xfs_atomic_write_cow_iomap_begin(
struct inode *inode,
@@ -1102,9 +1125,10 @@ xfs_atomic_write_cow_iomap_begin(
{
struct xfs_inode *ip = XFS_I(inode);
struct xfs_mount *mp = ip->i_mount;
const xfs_fileoff_t offset_fsb = XFS_B_TO_FSBT(mp, offset);
xfs_fileoff_t end_fsb = xfs_iomap_end_fsb(mp, offset, length);
xfs_filblks_t count_fsb = end_fsb - offset_fsb;
const xfs_fileoff_t offset_fsb = XFS_B_TO_FSBT(mp, offset);
const xfs_fileoff_t end_fsb = XFS_B_TO_FSB(mp, offset + length);
const xfs_filblks_t count_fsb = end_fsb - offset_fsb;
xfs_filblks_t hole_count_fsb;
int nmaps = 1;
xfs_filblks_t resaligned;
struct xfs_bmbt_irec cmap;
@@ -1130,7 +1154,7 @@ xfs_atomic_write_cow_iomap_begin(
return -EAGAIN;
trace_xfs_iomap_atomic_write_cow(ip, offset, length);
retry:
xfs_ilock(ip, XFS_ILOCK_EXCL);
if (!ip->i_cowfp) {
@@ -1141,14 +1165,22 @@ xfs_atomic_write_cow_iomap_begin(
if (!xfs_iext_lookup_extent(ip, ip->i_cowfp, offset_fsb, &icur, &cmap))
cmap.br_startoff = end_fsb;
if (cmap.br_startoff <= offset_fsb) {
if (isnullstartblock(cmap.br_startblock))
goto convert_delay;
/*
* cmap could extend outside the write range due to previous
* speculative preallocations. We must trim cmap to the write
* range because the cow fork treats written mappings to mean
* "write in progress".
*/
xfs_trim_extent(&cmap, offset_fsb, count_fsb);
goto found;
}
end_fsb = cmap.br_startoff;
count_fsb = end_fsb - offset_fsb;
hole_count_fsb = cmap.br_startoff - offset_fsb;
resaligned = xfs_aligned_fsb_count(offset_fsb, count_fsb,
resaligned = xfs_aligned_fsb_count(offset_fsb, hole_count_fsb,
xfs_get_cowextsz_hint(ip));
xfs_iunlock(ip, XFS_ILOCK_EXCL);
@@ -1169,8 +1201,10 @@ xfs_atomic_write_cow_iomap_begin(
if (!xfs_iext_lookup_extent(ip, ip->i_cowfp, offset_fsb, &icur, &cmap))
cmap.br_startoff = end_fsb;
if (cmap.br_startoff <= offset_fsb) {
xfs_trim_extent(&cmap, offset_fsb, count_fsb);
xfs_trans_cancel(tp);
if (isnullstartblock(cmap.br_startblock))
goto convert_delay;
xfs_trim_extent(&cmap, offset_fsb, count_fsb);
goto found;
}
@@ -1182,7 +1216,7 @@ xfs_atomic_write_cow_iomap_begin(
* atomic writes to that same range will be aligned (and don't require
* this COW-based method).
*/
error = xfs_bmapi_write(tp, ip, offset_fsb, count_fsb,
error = xfs_bmapi_write(tp, ip, offset_fsb, hole_count_fsb,
XFS_BMAPI_COWFORK | XFS_BMAPI_PREALLOC |
XFS_BMAPI_EXTSZALIGN, 0, &cmap, &nmaps);
if (error) {
@@ -1195,21 +1229,43 @@ xfs_atomic_write_cow_iomap_begin(
if (error)
goto out_unlock;
/*
* cmap could map more blocks than the range we passed into bmapi_write
* because of EXTSZALIGN or adjacent pre-existing unwritten mappings
* that were merged. Trim cmap to the original write range so that we
* don't convert more than we were asked to do for this write.
*/
xfs_trim_extent(&cmap, offset_fsb, count_fsb);
found:
if (cmap.br_state != XFS_EXT_NORM) {
error = xfs_reflink_convert_cow_locked(ip, offset_fsb,
count_fsb);
error = xfs_reflink_convert_cow_locked(ip, cmap.br_startoff,
cmap.br_blockcount);
if (error)
goto out_unlock;
cmap.br_state = XFS_EXT_NORM;
xfs_check_atomic_cow_conversion(ip, offset_fsb, count_fsb,
&cmap);
}
length = XFS_FSB_TO_B(mp, cmap.br_startoff + cmap.br_blockcount);
trace_xfs_iomap_found(ip, offset, length - offset, XFS_COW_FORK, &cmap);
trace_xfs_iomap_found(ip, offset, length, XFS_COW_FORK, &cmap);
seq = xfs_iomap_inode_sequence(ip, IOMAP_F_SHARED);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
return xfs_bmbt_to_iomap(ip, iomap, &cmap, flags, IOMAP_F_SHARED, seq);
convert_delay:
xfs_iunlock(ip, XFS_ILOCK_EXCL);
error = xfs_bmapi_convert_delalloc(ip, XFS_COW_FORK, offset, iomap,
NULL);
if (error)
return error;
/*
* Try the lookup again, because the delalloc conversion might have
* turned the COW mapping into unwritten, but we need it to be in
* written state.
*/
goto retry;
out_unlock:
xfs_iunlock(ip, XFS_ILOCK_EXCL);
return error;

View File

@@ -615,7 +615,7 @@ xfs_select_open_zone_mru(
lockdep_assert_held(&zi->zi_open_zones_lock);
list_for_each_entry_reverse(oz, &zi->zi_open_zones, oz_entry)
if (xfs_try_use_zone(zi, file_hint, oz, false))
if (xfs_try_use_zone(zi, file_hint, oz, XFS_ZONE_ALLOC_OK))
return oz;
cond_resched_lock(&zi->zi_open_zones_lock);
@@ -1249,8 +1249,10 @@ xfs_mount_zones(
while ((rtg = xfs_rtgroup_next(mp, rtg))) {
error = xfs_init_zone(&iz, rtg, NULL);
if (error)
if (error) {
xfs_rtgroup_rele(rtg);
goto out_free_zone_info;
}
}
}