--- /dev/null
+From 29eefa6d0d07e185f7bfe9576f91e6dba98189c2 Mon Sep 17 00:00:00 2001
+From: xiaoshoukui <xiaoshoukui@gmail.com>
+Date: Tue, 15 Aug 2023 02:55:59 -0400
+Subject: btrfs: fix BUG_ON condition in btrfs_cancel_balance
+
+From: xiaoshoukui <xiaoshoukui@gmail.com>
+
+commit 29eefa6d0d07e185f7bfe9576f91e6dba98189c2 upstream.
+
+Pausing and canceling balance can race to interrupt balance lead to BUG_ON
+panic in btrfs_cancel_balance. The BUG_ON condition in btrfs_cancel_balance
+does not take this race scenario into account.
+
+However, the race condition has no other side effects. We can fix that.
+
+Reproducing it with panic trace like this:
+
+ kernel BUG at fs/btrfs/volumes.c:4618!
+ RIP: 0010:btrfs_cancel_balance+0x5cf/0x6a0
+ Call Trace:
+ <TASK>
+ ? do_nanosleep+0x60/0x120
+ ? hrtimer_nanosleep+0xb7/0x1a0
+ ? sched_core_clone_cookie+0x70/0x70
+ btrfs_ioctl_balance_ctl+0x55/0x70
+ btrfs_ioctl+0xa46/0xd20
+ __x64_sys_ioctl+0x7d/0xa0
+ do_syscall_64+0x38/0x80
+ entry_SYSCALL_64_after_hwframe+0x63/0xcd
+
+ Race scenario as follows:
+ > mutex_unlock(&fs_info->balance_mutex);
+ > --------------------
+ > .......issue pause and cancel req in another thread
+ > --------------------
+ > ret = __btrfs_balance(fs_info);
+ >
+ > mutex_lock(&fs_info->balance_mutex);
+ > if (ret == -ECANCELED && atomic_read(&fs_info->balance_pause_req)) {
+ > btrfs_info(fs_info, "balance: paused");
+ > btrfs_exclop_balance(fs_info, BTRFS_EXCLOP_BALANCE_PAUSED);
+ > }
+
+CC: stable@vger.kernel.org # 4.19+
+Signed-off-by: xiaoshoukui <xiaoshoukui@ruijie.com.cn>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/volumes.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/fs/btrfs/volumes.c
++++ b/fs/btrfs/volumes.c
+@@ -4106,8 +4106,7 @@ int btrfs_cancel_balance(struct btrfs_fs
+ }
+ }
+
+- BUG_ON(fs_info->balance_ctl ||
+- test_bit(BTRFS_FS_BALANCE_RUNNING, &fs_info->flags));
++ ASSERT(!test_bit(BTRFS_FS_BALANCE_RUNNING, &fs_info->flags));
+ atomic_dec(&fs_info->balance_cancel_req);
+ mutex_unlock(&fs_info->balance_mutex);
+ return 0;