Commit 2e545d69 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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

Pull xfs fixes from Darrick Wong:

 - Fix a crash if mount time quotacheck fails when there are inodes
   queued for garbage collection.

 - Fix an off by one error when discarding folios after writeback
   failure.

* tag 'xfs-6.3-fixes-1' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux:
  xfs: fix off-by-one-block in xfs_discard_folio()
  xfs: quotacheck failure can race with background inode inactivation
parents 13423166 8ac5b996
Loading
Loading
Loading
Loading
+14 −7
Original line number Diff line number Diff line
@@ -449,15 +449,17 @@ xfs_prepare_ioend(
}

/*
 * If the page has delalloc blocks on it, we need to punch them out before we
 * invalidate the page.  If we don't, we leave a stale delalloc mapping on the
 * inode that can trip up a later direct I/O read operation on the same region.
 * If the folio has delalloc blocks on it, the caller is asking us to punch them
 * out. If we don't, we can leave a stale delalloc mapping covered by a clean
 * page that needs to be dirtied again before the delalloc mapping can be
 * converted. This stale delalloc mapping can trip up a later direct I/O read
 * operation on the same region.
 *
 * We prevent this by truncating away the delalloc regions on the page.  Because
 * We prevent this by truncating away the delalloc regions on the folio. Because
 * they are delalloc, we can do this without needing a transaction. Indeed - if
 * we get ENOSPC errors, we have to be able to do this truncation without a
 * transaction as there is no space left for block reservation (typically why we
 * see a ENOSPC in writeback).
 * transaction as there is no space left for block reservation (typically why
 * we see a ENOSPC in writeback).
 */
static void
xfs_discard_folio(
@@ -475,8 +477,13 @@ xfs_discard_folio(
		"page discard on page "PTR_FMT", inode 0x%llx, pos %llu.",
			folio, ip->i_ino, pos);

	/*
	 * The end of the punch range is always the offset of the the first
	 * byte of the next folio. Hence the end offset is only dependent on the
	 * folio itself and not the start offset that is passed in.
	 */
	error = xfs_bmap_punch_delalloc_range(ip, pos,
			round_up(pos, folio_size(folio)));
				folio_pos(folio) + folio_size(folio));

	if (error && !xfs_is_shutdown(mp))
		xfs_alert(mp, "page discard unable to remove delalloc mapping.");
+26 −14
Original line number Diff line number Diff line
@@ -1321,15 +1321,14 @@ xfs_qm_quotacheck(

	error = xfs_iwalk_threaded(mp, 0, 0, xfs_qm_dqusage_adjust, 0, true,
			NULL);
	if (error) {

	/*
		 * The inode walk may have partially populated the dquot
		 * caches.  We must purge them before disabling quota and
		 * tearing down the quotainfo, or else the dquots will leak.
	 * On error, the inode walk may have partially populated the dquot
	 * caches.  We must purge them before disabling quota and tearing down
	 * the quotainfo, or else the dquots will leak.
	 */
		xfs_qm_dqpurge_all(mp);
		goto error_return;
	}
	if (error)
		goto error_purge;

	/*
	 * We've made all the changes that we need to make incore.  Flush them
@@ -1363,10 +1362,8 @@ xfs_qm_quotacheck(
	 * and turn quotaoff. The dquots won't be attached to any of the inodes
	 * at this point (because we intentionally didn't in dqget_noattach).
	 */
	if (error) {
		xfs_qm_dqpurge_all(mp);
		goto error_return;
	}
	if (error)
		goto error_purge;

	/*
	 * If one type of quotas is off, then it will lose its
@@ -1395,6 +1392,21 @@ xfs_qm_quotacheck(
	} else
		xfs_notice(mp, "Quotacheck: Done.");
	return error;

error_purge:
	/*
	 * On error, we may have inodes queued for inactivation. This may try
	 * to attach dquots to the inode before running cleanup operations on
	 * the inode and this can race with the xfs_qm_destroy_quotainfo() call
	 * below that frees mp->m_quotainfo. To avoid this race, flush all the
	 * pending inodegc operations before we purge the dquots from memory,
	 * ensuring that background inactivation is idle whilst we turn off
	 * quotas.
	 */
	xfs_inodegc_flush(mp);
	xfs_qm_dqpurge_all(mp);
	goto error_return;

}

/*