| From 8a1f1e3d1eecf9d2359a2709e276743a67e145db Mon Sep 17 00:00:00 2001 |
| From: Filipe Manana <fdmanana@suse.com> |
| Date: Thu, 8 Sep 2022 12:31:50 +0100 |
| Subject: btrfs: fix hang during unmount when stopping block group reclaim worker |
| |
| From: Filipe Manana <fdmanana@suse.com> |
| |
| commit 8a1f1e3d1eecf9d2359a2709e276743a67e145db upstream. |
| |
| During early unmount, at close_ctree(), we try to stop the block group |
| reclaim task with cancel_work_sync(), but that may hang if the block group |
| reclaim task is currently at btrfs_relocate_block_group() waiting for the |
| flag BTRFS_FS_UNFINISHED_DROPS to be cleared from fs_info->flags. During |
| unmount we only clear that flag later, after trying to stop the block |
| group reclaim task. |
| |
| Fix that by clearing BTRFS_FS_UNFINISHED_DROPS before trying to stop the |
| block group reclaim task and after setting BTRFS_FS_CLOSING_START, so that |
| if the reclaim task is waiting on that bit, it will stop immediately after |
| being woken, because it sees the filesystem is closing (with a call to |
| btrfs_fs_closing()), and then returns immediately with -EINTR. |
| |
| Fixes: 31e70e527806c5 ("btrfs: fix hang during unmount when block group reclaim task is running") |
| CC: stable@vger.kernel.org # 5.15+ |
| Reviewed-by: Josef Bacik <josef@toxicpanda.com> |
| Signed-off-by: Filipe Manana <fdmanana@suse.com> |
| Signed-off-by: David Sterba <dsterba@suse.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| fs/btrfs/disk-io.c | 17 +++++++++++------ |
| 1 file changed, 11 insertions(+), 6 deletions(-) |
| |
| --- a/fs/btrfs/disk-io.c |
| +++ b/fs/btrfs/disk-io.c |
| @@ -4298,6 +4298,17 @@ void __cold close_ctree(struct btrfs_fs_ |
| set_bit(BTRFS_FS_CLOSING_START, &fs_info->flags); |
| |
| /* |
| + * If we had UNFINISHED_DROPS we could still be processing them, so |
| + * clear that bit and wake up relocation so it can stop. |
| + * We must do this before stopping the block group reclaim task, because |
| + * at btrfs_relocate_block_group() we wait for this bit, and after the |
| + * wait we stop with -EINTR if btrfs_fs_closing() returns non-zero - we |
| + * have just set BTRFS_FS_CLOSING_START, so btrfs_fs_closing() will |
| + * return 1. |
| + */ |
| + btrfs_wake_unfinished_drop(fs_info); |
| + |
| + /* |
| * We may have the reclaim task running and relocating a data block group, |
| * in which case it may create delayed iputs. So stop it before we park |
| * the cleaner kthread otherwise we can get new delayed iputs after |
| @@ -4315,12 +4326,6 @@ void __cold close_ctree(struct btrfs_fs_ |
| */ |
| kthread_park(fs_info->cleaner_kthread); |
| |
| - /* |
| - * If we had UNFINISHED_DROPS we could still be processing them, so |
| - * clear that bit and wake up relocation so it can stop. |
| - */ |
| - btrfs_wake_unfinished_drop(fs_info); |
| - |
| /* wait for the qgroup rescan worker to stop */ |
| btrfs_qgroup_wait_for_completion(fs_info, false); |
| |