Commit 4f24a767 authored by Yuto Ohnuki's avatar Yuto Ohnuki Committed by Carlos Maiolino
Browse files

xfs: stop reclaim before pushing AIL during unmount



The unmount sequence in xfs_unmount_flush_inodes() pushed the AIL while
background reclaim and inodegc are still running. This is broken
independently of any use-after-free issues - background reclaim and
inodegc should not be running while the AIL is being pushed during
unmount, as inodegc can dirty and insert inodes into the AIL during the
flush, and background reclaim can race to abort and free dirty inodes.

Reorder xfs_unmount_flush_inodes() to stop inodegc and cancel background
reclaim before pushing the AIL. Stop inodegc before cancelling
m_reclaim_work because the inodegc worker can re-queue m_reclaim_work
via xfs_inodegc_set_reclaimable.

Reported-by: default avatar <syzbot+652af2b3c5569c4ab63c@syzkaller.appspotmail.com>
Closes: https://syzkaller.appspot.com/bug?extid=652af2b3c5569c4ab63c


Fixes: 90c60e16 ("xfs: xfs_iflush() is no longer necessary")
Cc: stable@vger.kernel.org # v5.9
Signed-off-by: default avatarYuto Ohnuki <ytohnuki@amazon.com>
Reviewed-by: default avatarDarrick J. Wong <djwong@kernel.org>
Signed-off-by: default avatarCarlos Maiolino <cem@kernel.org>
parent 362c4909
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -608,8 +608,9 @@ xfs_unmount_check(
 * have been retrying in the background.  This will prevent never-ending
 * retries in AIL pushing from hanging the unmount.
 *
 * Finally, we can push the AIL to clean all the remaining dirty objects, then
 * reclaim the remaining inodes that are still in memory at this point in time.
 * Stop inodegc and background reclaim before pushing the AIL so that they
 * are not running while the AIL is being flushed. Then push the AIL to
 * clean all the remaining dirty objects and reclaim the remaining inodes.
 */
static void
xfs_unmount_flush_inodes(
@@ -621,9 +622,9 @@ xfs_unmount_flush_inodes(

	xfs_set_unmounting(mp);

	xfs_ail_push_all_sync(mp->m_ail);
	xfs_inodegc_stop(mp);
	cancel_delayed_work_sync(&mp->m_reclaim_work);
	xfs_ail_push_all_sync(mp->m_ail);
	xfs_reclaim_inodes(mp);
	xfs_health_unmount(mp);
	xfs_healthmon_unmount(mp);