| From 6af112b11a4bc1b560f60a618ac9c1dcefe9836e Mon Sep 17 00:00:00 2001 |
| From: Nikolay Borisov <nborisov@suse.com> |
| Date: Wed, 4 Sep 2019 19:33:58 +0300 |
| Subject: btrfs: Relinquish CPUs in btrfs_compare_trees |
| |
| From: Nikolay Borisov <nborisov@suse.com> |
| |
| commit 6af112b11a4bc1b560f60a618ac9c1dcefe9836e upstream. |
| |
| When doing any form of incremental send the parent and the child trees |
| need to be compared via btrfs_compare_trees. This can result in long |
| loop chains without ever relinquishing the CPU. This causes softlockup |
| detector to trigger when comparing trees with a lot of items. Example |
| report: |
| |
| watchdog: BUG: soft lockup - CPU#0 stuck for 24s! [snapperd:16153] |
| CPU: 0 PID: 16153 Comm: snapperd Not tainted 5.2.9-1-default #1 openSUSE Tumbleweed (unreleased) |
| Hardware name: QEMU KVM Virtual Machine, BIOS 0.0.0 02/06/2015 |
| pstate: 40000005 (nZcv daif -PAN -UAO) |
| pc : __ll_sc_arch_atomic_sub_return+0x14/0x20 |
| lr : btrfs_release_extent_buffer_pages+0xe0/0x1e8 [btrfs] |
| sp : ffff00001273b7e0 |
| Call trace: |
| __ll_sc_arch_atomic_sub_return+0x14/0x20 |
| release_extent_buffer+0xdc/0x120 [btrfs] |
| free_extent_buffer.part.0+0xb0/0x118 [btrfs] |
| free_extent_buffer+0x24/0x30 [btrfs] |
| btrfs_release_path+0x4c/0xa0 [btrfs] |
| btrfs_free_path.part.0+0x20/0x40 [btrfs] |
| btrfs_free_path+0x24/0x30 [btrfs] |
| get_inode_info+0xa8/0xf8 [btrfs] |
| finish_inode_if_needed+0xe0/0x6d8 [btrfs] |
| changed_cb+0x9c/0x410 [btrfs] |
| btrfs_compare_trees+0x284/0x648 [btrfs] |
| send_subvol+0x33c/0x520 [btrfs] |
| btrfs_ioctl_send+0x8a0/0xaf0 [btrfs] |
| btrfs_ioctl+0x199c/0x2288 [btrfs] |
| do_vfs_ioctl+0x4b0/0x820 |
| ksys_ioctl+0x84/0xb8 |
| __arm64_sys_ioctl+0x28/0x38 |
| el0_svc_common.constprop.0+0x7c/0x188 |
| el0_svc_handler+0x34/0x90 |
| el0_svc+0x8/0xc |
| |
| Fix this by adding a call to cond_resched at the beginning of the main |
| loop in btrfs_compare_trees. |
| |
| Fixes: 7069830a9e38 ("Btrfs: add btrfs_compare_trees function") |
| CC: stable@vger.kernel.org # 4.4+ |
| Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de> |
| Signed-off-by: Nikolay Borisov <nborisov@suse.com> |
| 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/ctree.c | 1 + |
| 1 file changed, 1 insertion(+) |
| |
| --- a/fs/btrfs/ctree.c |
| +++ b/fs/btrfs/ctree.c |
| @@ -5467,6 +5467,7 @@ int btrfs_compare_trees(struct btrfs_roo |
| advance_left = advance_right = 0; |
| |
| while (1) { |
| + cond_resched(); |
| if (advance_left && !left_end_reached) { |
| ret = tree_advance(left_root, left_path, &left_level, |
| left_root_level, |