Commit e284d511 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
parents e811c33b d8a823c6
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -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
+69 −13
Original line number Diff line number Diff line
@@ -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,
@@ -1103,8 +1126,9 @@ 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	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;
+4 −2
Original line number Diff line number Diff line
@@ -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,10 +1249,12 @@ 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;
			}
		}
	}

	xfs_set_freecounter(mp, XC_FREE_RTAVAILABLE, iz.available);
	xfs_set_freecounter(mp, XC_FREE_RTEXTENTS,