Unverified Commit 5521330a authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!6758 CVE-2022-48664

Merge Pull Request from: @ci-robot 
 
PR sync from: Yifan Qiao <qiaoyifan4@huawei.com>
https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/2E5YX3SFGTFOOAVTNBFB223E3SSBPGHP/ 
Filipe Manana (2):
  Btrfs: fix crash during unmount due to race with delayed inode workers
  btrfs: fix hang during unmount when stopping a space reclaim worker


-- 
2.39.2
 
https://gitee.com/src-openeuler/kernel/issues/I9KHGY 
 
Link:https://gitee.com/openeuler/kernel/pulls/6758

 

Reviewed-by: default avatarzhangyi (F) <yi.zhang@huawei.com>
Reviewed-by: default avatarLiu YongQiang <liuyongqiang13@huawei.com>
Signed-off-by: default avatarZhang Changzhong <zhangchangzhong@huawei.com>
parents f3d58fc0 4586a194
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -434,3 +434,11 @@ void btrfs_set_work_high_priority(struct btrfs_work *work)
{
	set_bit(WORK_HIGH_PRIO_BIT, &work->flags);
}

void btrfs_flush_workqueue(struct btrfs_workqueue *wq)
{
	if (wq->high)
		flush_workqueue(wq->high->normal_wq);

	flush_workqueue(wq->normal->normal_wq);
}
+1 −0
Original line number Diff line number Diff line
@@ -73,5 +73,6 @@ void btrfs_set_work_high_priority(struct btrfs_work *work);
struct btrfs_fs_info *btrfs_work_owner(const struct btrfs_work *work);
struct btrfs_fs_info *btrfs_workqueue_owner(const struct __btrfs_workqueue *wq);
bool btrfs_workqueue_normal_congested(const struct btrfs_workqueue *wq);
void btrfs_flush_workqueue(struct btrfs_workqueue *wq);

#endif
+38 −0
Original line number Diff line number Diff line
@@ -3939,6 +3939,31 @@ void close_ctree(struct btrfs_fs_info *fs_info)
	/* clear out the rbtree of defraggable inodes */
	btrfs_cleanup_defrag_inodes(fs_info);

	/*
	 * After we parked the cleaner kthread, ordered extents may have
	 * completed and created new delayed iputs. If one of the async reclaim
	 * tasks is running and in the RUN_DELAYED_IPUTS flush state, then we
	 * can hang forever trying to stop it, because if a delayed iput is
	 * added after it ran btrfs_run_delayed_iputs() and before it called
	 * btrfs_wait_on_delayed_iputs(), it will hang forever since there is
	 * no one else to run iputs.
	 *
	 * So wait for all ongoing ordered extents to complete and then run
	 * delayed iputs. This works because once we reach this point no one
	 * can either create new ordered extents nor create delayed iputs
	 * through some other means.
	 *
	 * Also note that btrfs_wait_ordered_roots() is not safe here, because
	 * it waits for BTRFS_ORDERED_COMPLETE to be set on an ordered extent,
	 * but the delayed iput for the respective inode is made only when doing
	 * the final btrfs_put_ordered_extent() (which must happen at
	 * btrfs_finish_ordered_io() when we are unmounting).
	 */
	btrfs_flush_workqueue(fs_info->endio_write_workers);
	/* Ordered extents for free space inodes. */
	btrfs_flush_workqueue(fs_info->endio_freespace_worker);
	btrfs_run_delayed_iputs(fs_info);

	cancel_work_sync(&fs_info->async_reclaim_work);

	if (!sb_rdonly(fs_info->sb)) {
@@ -3948,6 +3973,19 @@ void close_ctree(struct btrfs_fs_info *fs_info)
		 */
		btrfs_delete_unused_bgs(fs_info);

		/*
		 * There might be existing delayed inode workers still running
		 * and holding an empty delayed inode item. We must wait for
		 * them to complete first because they can create a transaction.
		 * This happens when someone calls btrfs_balance_delayed_items()
		 * and then a transaction commit runs the same delayed nodes
		 * before any delayed worker has done something with the nodes.
		 * We must wait for any worker here and not at transaction
		 * commit time since that could cause a deadlock.
		 * This is a very rare case.
		 */
		btrfs_flush_workqueue(fs_info->delayed_workers);

		ret = btrfs_commit_super(fs_info);
		if (ret)
			btrfs_err(fs_info, "commit super ret %d", ret);