]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 24 Jul 2020 09:47:05 +0000 (11:47 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 24 Jul 2020 09:47:05 +0000 (11:47 +0200)
added patches:
btrfs-reloc-clear-dead_reloc_tree-bit-for-orphan-roots-to-prevent-runaway-balance.patch
btrfs-reloc-fix-reloc-root-leak-and-null-pointer-dereference.patch

queue-5.4/btrfs-reloc-clear-dead_reloc_tree-bit-for-orphan-roots-to-prevent-runaway-balance.patch [new file with mode: 0644]
queue-5.4/btrfs-reloc-fix-reloc-root-leak-and-null-pointer-dereference.patch [new file with mode: 0644]
queue-5.4/series

diff --git a/queue-5.4/btrfs-reloc-clear-dead_reloc_tree-bit-for-orphan-roots-to-prevent-runaway-balance.patch b/queue-5.4/btrfs-reloc-clear-dead_reloc_tree-bit-for-orphan-roots-to-prevent-runaway-balance.patch
new file mode 100644 (file)
index 0000000..57b867a
--- /dev/null
@@ -0,0 +1,56 @@
+From 1dae7e0e58b484eaa43d530f211098fdeeb0f404 Mon Sep 17 00:00:00 2001
+From: Qu Wenruo <wqu@suse.com>
+Date: Wed, 20 May 2020 14:58:51 +0800
+Subject: btrfs: reloc: clear DEAD_RELOC_TREE bit for orphan roots to prevent runaway balance
+
+From: Qu Wenruo <wqu@suse.com>
+
+commit 1dae7e0e58b484eaa43d530f211098fdeeb0f404 upstream.
+
+[BUG]
+There are several reported runaway balance, that balance is flooding the
+log with "found X extents" where the X never changes.
+
+[CAUSE]
+Commit d2311e698578 ("btrfs: relocation: Delay reloc tree deletion after
+merge_reloc_roots") introduced BTRFS_ROOT_DEAD_RELOC_TREE bit to
+indicate that one subvolume has finished its tree blocks swap with its
+reloc tree.
+
+However if balance is canceled or hits ENOSPC halfway, we didn't clear
+the BTRFS_ROOT_DEAD_RELOC_TREE bit, leaving that bit hanging forever
+until unmount.
+
+Any subvolume root with that bit, would cause backref cache to skip this
+tree block, as it has finished its tree block swap.  This would cause
+all tree blocks of that root be ignored by balance, leading to runaway
+balance.
+
+[FIX]
+Fix the problem by also clearing the BTRFS_ROOT_DEAD_RELOC_TREE bit for
+the original subvolume of orphan reloc root.
+
+Add an umount check for the stale bit still set.
+
+Fixes: d2311e698578 ("btrfs: relocation: Delay reloc tree deletion after merge_reloc_roots")
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+[Manually solve the conflicts due to no btrfs root refs rework]
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/btrfs/relocation.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/fs/btrfs/relocation.c
++++ b/fs/btrfs/relocation.c
+@@ -2540,6 +2540,8 @@ again:
+                       if (!IS_ERR(root)) {
+                               if (root->reloc_root == reloc_root)
+                                       root->reloc_root = NULL;
++                              clear_bit(BTRFS_ROOT_DEAD_RELOC_TREE,
++                                        &root->state);
+                       }
+                       list_del_init(&reloc_root->root_list);
diff --git a/queue-5.4/btrfs-reloc-fix-reloc-root-leak-and-null-pointer-dereference.patch b/queue-5.4/btrfs-reloc-fix-reloc-root-leak-and-null-pointer-dereference.patch
new file mode 100644 (file)
index 0000000..f0d35b3
--- /dev/null
@@ -0,0 +1,133 @@
+From 51415b6c1b117e223bc083e30af675cb5c5498f3 Mon Sep 17 00:00:00 2001
+From: Qu Wenruo <wqu@suse.com>
+Date: Tue, 19 May 2020 10:13:20 +0800
+Subject: btrfs: reloc: fix reloc root leak and NULL pointer dereference
+
+From: Qu Wenruo <wqu@suse.com>
+
+commit 51415b6c1b117e223bc083e30af675cb5c5498f3 upstream.
+
+[BUG]
+When balance is canceled, there is a pretty high chance that unmounting
+the fs can lead to lead the NULL pointer dereference:
+
+  BTRFS warning (device dm-3): page private not zero on page 223158272
+  ...
+  BTRFS warning (device dm-3): page private not zero on page 223162368
+  BTRFS error (device dm-3): leaked root 18446744073709551608-304 refcount 1
+  BUG: kernel NULL pointer dereference, address: 0000000000000168
+  #PF: supervisor read access in kernel mode
+  #PF: error_code(0x0000) - not-present page
+  PGD 0 P4D 0
+  Oops: 0000 [#1] PREEMPT SMP NOPTI
+  CPU: 2 PID: 5793 Comm: umount Tainted: G           O      5.7.0-rc5-custom+ #53
+  Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015
+  RIP: 0010:__lock_acquire+0x5dc/0x24c0
+  Call Trace:
+   lock_acquire+0xab/0x390
+   _raw_spin_lock+0x39/0x80
+   btrfs_release_extent_buffer_pages+0xd7/0x200 [btrfs]
+   release_extent_buffer+0xb2/0x170 [btrfs]
+   free_extent_buffer+0x66/0xb0 [btrfs]
+   btrfs_put_root+0x8e/0x130 [btrfs]
+   btrfs_check_leaked_roots.cold+0x5/0x5d [btrfs]
+   btrfs_free_fs_info+0xe5/0x120 [btrfs]
+   btrfs_kill_super+0x1f/0x30 [btrfs]
+   deactivate_locked_super+0x3b/0x80
+   deactivate_super+0x3e/0x50
+   cleanup_mnt+0x109/0x160
+   __cleanup_mnt+0x12/0x20
+   task_work_run+0x67/0xa0
+   exit_to_usermode_loop+0xc5/0xd0
+   syscall_return_slowpath+0x205/0x360
+   do_syscall_64+0x6e/0xb0
+   entry_SYSCALL_64_after_hwframe+0x49/0xb3
+  RIP: 0033:0x7fd028ef740b
+
+[CAUSE]
+When balance is canceled, all reloc roots are marked as orphan, and
+orphan reloc roots are going to be cleaned up.
+
+However for orphan reloc roots and merged reloc roots, their lifespan
+are quite different:
+
+       Merged reloc roots      |       Orphan reloc roots by cancel
+--------------------------------------------------------------------
+create_reloc_root()            | create_reloc_root()
+|- refs == 1                   | |- refs == 1
+                               |
+btrfs_grab_root(reloc_root);   | btrfs_grab_root(reloc_root);
+|- refs == 2                   | |- refs == 2
+                               |
+root->reloc_root = reloc_root; | root->reloc_root = reloc_root;
+               >>> No difference so far <<<
+                               |
+prepare_to_merge()             | prepare_to_merge()
+|- btrfs_set_root_refs(item, 1);| |- if (!err) (err == -EINTR)
+                               |
+merge_reloc_roots()            | merge_reloc_roots()
+|- merge_reloc_root()          | |- Doing nothing to put reloc root
+   |- insert_dirty_subvol()    | |- refs == 2
+      |- __del_reloc_root()    |
+         |- btrfs_put_root()   |
+            |- refs == 1       |
+               >>> Now orphan reloc roots still have refs 2 <<<
+                               |
+clean_dirty_subvols()          | clean_dirty_subvols()
+|- btrfs_drop_snapshot()       | |- btrfS_drop_snapshot()
+   |- reloc_root get freed     |    |- reloc_root still has refs 2
+                               |       related ebs get freed, but
+                               |       reloc_root still recorded in
+                               |       allocated_roots
+btrfs_check_leaked_roots()     | btrfs_check_leaked_roots()
+|- No leaked roots             | |- Leaked reloc_roots detected
+                               | |- btrfs_put_root()
+                               |    |- free_extent_buffer(root->node);
+                               |       |- eb already freed, caused NULL
+                               |          pointer dereference
+
+[FIX]
+The fix is to clear fs_root->reloc_root and put it at
+merge_reloc_roots() time, so that we won't leak reloc roots.
+
+Fixes: d2311e698578 ("btrfs: relocation: Delay reloc tree deletion after merge_reloc_roots")
+CC: stable@vger.kernel.org # 5.1+
+Tested-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+[Manually solve the conflicts due to no btrfs root refs rework]
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/btrfs/relocation.c |    9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+--- a/fs/btrfs/relocation.c
++++ b/fs/btrfs/relocation.c
+@@ -2525,12 +2525,10 @@ again:
+               reloc_root = list_entry(reloc_roots.next,
+                                       struct btrfs_root, root_list);
++              root = read_fs_root(fs_info, reloc_root->root_key.offset);
+               if (btrfs_root_refs(&reloc_root->root_item) > 0) {
+-                      root = read_fs_root(fs_info,
+-                                          reloc_root->root_key.offset);
+                       BUG_ON(IS_ERR(root));
+                       BUG_ON(root->reloc_root != reloc_root);
+-
+                       ret = merge_reloc_root(rc, root);
+                       if (ret) {
+                               if (list_empty(&reloc_root->root_list))
+@@ -2539,6 +2537,11 @@ again:
+                               goto out;
+                       }
+               } else {
++                      if (!IS_ERR(root)) {
++                              if (root->reloc_root == reloc_root)
++                                      root->reloc_root = NULL;
++                      }
++
+                       list_del_init(&reloc_root->root_list);
+                       /* Don't forget to queue this reloc root for cleanup */
+                       list_add_tail(&reloc_root->reloc_dirty_list,
index 056aa040d3eeeca88206e03ef5fa3fb8cb0c846d..e29016904d2dbfcae1043085c340a47b90e32c7d 100644 (file)
@@ -24,3 +24,5 @@ drm-amd-display-check-dmcu-exists-before-loading.patch
 dm-mpath-pass-io-start-time-to-path-selector.patch
 dm-do-not-use-waitqueue-for-request-based-dm.patch
 sunrpc-reverting-d03727b248d0-nfsv4-fix-close-not-waiting-for-direct-io-compeletion.patch
+btrfs-reloc-fix-reloc-root-leak-and-null-pointer-dereference.patch
+btrfs-reloc-clear-dead_reloc_tree-bit-for-orphan-roots-to-prevent-runaway-balance.patch