]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.9-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 7 May 2021 15:31:11 +0000 (17:31 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 7 May 2021 15:31:11 +0000 (17:31 +0200)
added patches:
btrfs-fix-metadata-extent-leak-after-failure-to-create-subvolume.patch

queue-4.9/btrfs-fix-metadata-extent-leak-after-failure-to-create-subvolume.patch [new file with mode: 0644]
queue-4.9/series

diff --git a/queue-4.9/btrfs-fix-metadata-extent-leak-after-failure-to-create-subvolume.patch b/queue-4.9/btrfs-fix-metadata-extent-leak-after-failure-to-create-subvolume.patch
new file mode 100644 (file)
index 0000000..e349fca
--- /dev/null
@@ -0,0 +1,95 @@
+From 67addf29004c5be9fa0383c82a364bb59afc7f84 Mon Sep 17 00:00:00 2001
+From: Filipe Manana <fdmanana@suse.com>
+Date: Tue, 20 Apr 2021 10:55:12 +0100
+Subject: btrfs: fix metadata extent leak after failure to create subvolume
+
+From: Filipe Manana <fdmanana@suse.com>
+
+commit 67addf29004c5be9fa0383c82a364bb59afc7f84 upstream.
+
+When creating a subvolume we allocate an extent buffer for its root node
+after starting a transaction. We setup a root item for the subvolume that
+points to that extent buffer and then attempt to insert the root item into
+the root tree - however if that fails, due to ENOMEM for example, we do
+not free the extent buffer previously allocated and we do not abort the
+transaction (as at that point we did nothing that can not be undone).
+
+This means that we effectively do not return the metadata extent back to
+the free space cache/tree and we leave a delayed reference for it which
+causes a metadata extent item to be added to the extent tree, in the next
+transaction commit, without having backreferences. When this happens
+'btrfs check' reports the following:
+
+  $ btrfs check /dev/sdi
+  Opening filesystem to check...
+  Checking filesystem on /dev/sdi
+  UUID: dce2cb9d-025f-4b05-a4bf-cee0ad3785eb
+  [1/7] checking root items
+  [2/7] checking extents
+  ref mismatch on [30425088 16384] extent item 1, found 0
+  backref 30425088 root 256 not referenced back 0x564a91c23d70
+  incorrect global backref count on 30425088 found 1 wanted 0
+  backpointer mismatch on [30425088 16384]
+  owner ref check failed [30425088 16384]
+  ERROR: errors found in extent allocation tree or chunk allocation
+  [3/7] checking free space cache
+  [4/7] checking fs roots
+  [5/7] checking only csums items (without verifying data)
+  [6/7] checking root refs
+  [7/7] checking quota groups skipped (not enabled on this FS)
+  found 212992 bytes used, error(s) found
+  total csum bytes: 0
+  total tree bytes: 131072
+  total fs tree bytes: 32768
+  total extent tree bytes: 16384
+  btree space waste bytes: 124669
+  file data blocks allocated: 65536
+   referenced 65536
+
+So fix this by freeing the metadata extent if btrfs_insert_root() returns
+an error.
+
+CC: stable@vger.kernel.org # 4.4+
+Signed-off-by: Filipe Manana <fdmanana@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/ioctl.c |   18 +++++++++++++++---
+ 1 file changed, 15 insertions(+), 3 deletions(-)
+
+--- a/fs/btrfs/ioctl.c
++++ b/fs/btrfs/ioctl.c
+@@ -557,8 +557,6 @@ static noinline int create_subvol(struct
+       btrfs_set_root_otransid(root_item, trans->transid);
+       btrfs_tree_unlock(leaf);
+-      free_extent_buffer(leaf);
+-      leaf = NULL;
+       btrfs_set_root_dirid(root_item, new_dirid);
+@@ -567,8 +565,22 @@ static noinline int create_subvol(struct
+       key.type = BTRFS_ROOT_ITEM_KEY;
+       ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key,
+                               root_item);
+-      if (ret)
++      if (ret) {
++              /*
++               * Since we don't abort the transaction in this case, free the
++               * tree block so that we don't leak space and leave the
++               * filesystem in an inconsistent state (an extent item in the
++               * extent tree without backreferences). Also no need to have
++               * the tree block locked since it is not in any tree at this
++               * point, so no other task can find it and use it.
++               */
++              btrfs_free_tree_block(trans, root, leaf, 0, 1);
++              free_extent_buffer(leaf);
+               goto fail;
++      }
++
++      free_extent_buffer(leaf);
++      leaf = NULL;
+       key.offset = (u64)-1;
+       new_root = btrfs_read_fs_root_no_name(root->fs_info, &key);
index a80970bf1785c12a8e43c791b259fb3d6321c6d0..feb98e1c8a5a32719dc05dab72a4185c4cd0ac97 100644 (file)
@@ -11,3 +11,4 @@ arm64-dts-mt8173-fix-property-typo-of-phys-in-dsi-node.patch
 ecryptfs-fix-kernel-panic-with-null-dev_name.patch
 mmc-core-do-a-power-cycle-when-the-cmd11-fails.patch
 mmc-core-set-read-only-for-sd-cards-with-permanent-write-protect-bit.patch
+btrfs-fix-metadata-extent-leak-after-failure-to-create-subvolume.patch