]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
lots of broken btrfs patches dropped
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 21 May 2018 07:05:54 +0000 (09:05 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 21 May 2018 07:05:54 +0000 (09:05 +0200)
queue-4.14/btrfs-fix-delalloc-inodes-invalidation-during-transaction-abort.patch [deleted file]
queue-4.14/series
queue-4.16/btrfs-fix-delalloc-inodes-invalidation-during-transaction-abort.patch [deleted file]
queue-4.16/series
queue-4.4/btrfs-send-fix-invalid-access-to-commit-roots-due-to-concurrent-snapshotting.patch [deleted file]
queue-4.4/series
queue-4.9/btrfs-send-fix-invalid-access-to-commit-roots-due-to-concurrent-snapshotting.patch [deleted file]
queue-4.9/series

diff --git a/queue-4.14/btrfs-fix-delalloc-inodes-invalidation-during-transaction-abort.patch b/queue-4.14/btrfs-fix-delalloc-inodes-invalidation-during-transaction-abort.patch
deleted file mode 100644 (file)
index ee15a67..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-From fe816d0f1d4c31c4c31d42ca78a87660565fc800 Mon Sep 17 00:00:00 2001
-From: Nikolay Borisov <nborisov@suse.com>
-Date: Fri, 27 Apr 2018 12:21:53 +0300
-Subject: btrfs: Fix delalloc inodes invalidation during transaction abort
-
-From: Nikolay Borisov <nborisov@suse.com>
-
-commit fe816d0f1d4c31c4c31d42ca78a87660565fc800 upstream.
-
-When a transaction is aborted btrfs_cleanup_transaction is called to
-cleanup all the various in-flight bits and pieces which migth be
-active. One of those is delalloc inodes - inodes which have dirty
-pages which haven't been persisted yet. Currently the process of
-freeing such delalloc inodes in exceptional circumstances such as
-transaction abort boiled down to calling btrfs_invalidate_inodes whose
-sole job is to invalidate the dentries for all inodes related to a
-root. This is in fact wrong and insufficient since such delalloc inodes
-will likely have pending pages or ordered-extents and will be linked to
-the sb->s_inode_list. This means that unmounting a btrfs instance with
-an aborted transaction could potentially lead inodes/their pages
-visible to the system long after their superblock has been freed. This
-in turn leads to a "use-after-free" situation once page shrink is
-triggered. This situation could be simulated by running generic/019
-which would cause such inodes to be left hanging, followed by
-generic/176 which causes memory pressure and page eviction which lead
-to touching the freed super block instance. This situation is
-additionally detected by the unmount code of VFS with the following
-message:
-
-"VFS: Busy inodes after unmount of Self-destruct in 5 seconds.  Have a nice day..."
-
-Additionally btrfs hits WARN_ON(!RB_EMPTY_ROOT(&root->inode_tree));
-in free_fs_root for the same reason.
-
-This patch aims to rectify the sitaution by doing the following:
-
-1. Change btrfs_destroy_delalloc_inodes so that it calls
-invalidate_inode_pages2 for every inode on the delalloc list, this
-ensures that all the pages of the inode are released. This function
-boils down to calling btrfs_releasepage. During test I observed cases
-where inodes on the delalloc list were having an i_count of 0, so this
-necessitates using igrab to be sure we are working on a non-freed inode.
-
-2. Since calling btrfs_releasepage might queue delayed iputs move the
-call out to btrfs_cleanup_transaction in btrfs_error_commit_super before
-calling run_delayed_iputs for the last time. This is necessary to ensure
-that delayed iputs are run.
-
-Note: this patch is tagged for 4.14 stable but the fix applies to older
-versions too but needs to be backported manually due to conflicts.
-
-CC: stable@vger.kernel.org # 4.14.x: 2b8773313494: btrfs: Split btrfs_del_delalloc_inode into 2 functions
-CC: stable@vger.kernel.org # 4.14.x
-Signed-off-by: Nikolay Borisov <nborisov@suse.com>
-Reviewed-by: David Sterba <dsterba@suse.com>
-[ add comment to igrab ]
-Signed-off-by: David Sterba <dsterba@suse.com>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-
----
- fs/btrfs/disk-io.c |   26 +++++++++++++++-----------
- 1 file changed, 15 insertions(+), 11 deletions(-)
-
---- a/fs/btrfs/disk-io.c
-+++ b/fs/btrfs/disk-io.c
-@@ -3905,6 +3905,7 @@ void close_ctree(struct btrfs_fs_info *f
-       set_bit(BTRFS_FS_CLOSING_DONE, &fs_info->flags);
-       btrfs_free_qgroup_config(fs_info);
-+      ASSERT(list_empty(&fs_info->delalloc_roots));
-       if (percpu_counter_sum(&fs_info->delalloc_bytes)) {
-               btrfs_info(fs_info, "at unmount delalloc count %lld",
-@@ -4203,15 +4204,15 @@ static int btrfs_check_super_valid(struc
- static void btrfs_error_commit_super(struct btrfs_fs_info *fs_info)
- {
-+      /* cleanup FS via transaction */
-+      btrfs_cleanup_transaction(fs_info);
-+
-       mutex_lock(&fs_info->cleaner_mutex);
-       btrfs_run_delayed_iputs(fs_info);
-       mutex_unlock(&fs_info->cleaner_mutex);
-       down_write(&fs_info->cleanup_work_sem);
-       up_write(&fs_info->cleanup_work_sem);
--
--      /* cleanup FS via transaction */
--      btrfs_cleanup_transaction(fs_info);
- }
- static void btrfs_destroy_ordered_extents(struct btrfs_root *root)
-@@ -4334,19 +4335,23 @@ static void btrfs_destroy_delalloc_inode
-       list_splice_init(&root->delalloc_inodes, &splice);
-       while (!list_empty(&splice)) {
-+              struct inode *inode = NULL;
-               btrfs_inode = list_first_entry(&splice, struct btrfs_inode,
-                                              delalloc_inodes);
--
--              list_del_init(&btrfs_inode->delalloc_inodes);
--              clear_bit(BTRFS_INODE_IN_DELALLOC_LIST,
--                        &btrfs_inode->runtime_flags);
-+              __btrfs_del_delalloc_inode(root, btrfs_inode);
-               spin_unlock(&root->delalloc_lock);
--              btrfs_invalidate_inodes(btrfs_inode->root);
--
-+              /*
-+               * Make sure we get a live inode and that it'll not disappear
-+               * meanwhile.
-+               */
-+              inode = igrab(&btrfs_inode->vfs_inode);
-+              if (inode) {
-+                      invalidate_inode_pages2(inode->i_mapping);
-+                      iput(inode);
-+              }
-               spin_lock(&root->delalloc_lock);
-       }
--
-       spin_unlock(&root->delalloc_lock);
- }
-@@ -4362,7 +4367,6 @@ static void btrfs_destroy_all_delalloc_i
-       while (!list_empty(&splice)) {
-               root = list_first_entry(&splice, struct btrfs_root,
-                                        delalloc_root);
--              list_del_init(&root->delalloc_root);
-               root = btrfs_grab_fs_root(root);
-               BUG_ON(!root);
-               spin_unlock(&fs_info->delalloc_root_lock);
index 92236ae9b34201d5bdac6532632bc70f07a61807..d9d590b6be5fc1353daf8d3509aed25c74811dc8 100644 (file)
@@ -38,7 +38,6 @@ tick-broadcast-use-for_each_cpu-specially-on-up-kernels.patch
 arm-8769-1-kprobes-fix-to-use-get_kprobe_ctlblk-after-irq-disabed.patch
 arm-8770-1-kprobes-prohibit-probing-on-optimized_callback.patch
 arm-8772-1-kprobes-prohibit-kprobes-on-get_user-functions.patch
-btrfs-fix-delalloc-inodes-invalidation-during-transaction-abort.patch
 btrfs-fix-xattr-loss-after-power-failure.patch
 btrfs-send-fix-invalid-access-to-commit-roots-due-to-concurrent-snapshotting.patch
 btrfs-property-set-incompat-flag-if-lzo-zstd-compression-is-set.patch
diff --git a/queue-4.16/btrfs-fix-delalloc-inodes-invalidation-during-transaction-abort.patch b/queue-4.16/btrfs-fix-delalloc-inodes-invalidation-during-transaction-abort.patch
deleted file mode 100644 (file)
index 939bf88..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-From fe816d0f1d4c31c4c31d42ca78a87660565fc800 Mon Sep 17 00:00:00 2001
-From: Nikolay Borisov <nborisov@suse.com>
-Date: Fri, 27 Apr 2018 12:21:53 +0300
-Subject: btrfs: Fix delalloc inodes invalidation during transaction abort
-
-From: Nikolay Borisov <nborisov@suse.com>
-
-commit fe816d0f1d4c31c4c31d42ca78a87660565fc800 upstream.
-
-When a transaction is aborted btrfs_cleanup_transaction is called to
-cleanup all the various in-flight bits and pieces which migth be
-active. One of those is delalloc inodes - inodes which have dirty
-pages which haven't been persisted yet. Currently the process of
-freeing such delalloc inodes in exceptional circumstances such as
-transaction abort boiled down to calling btrfs_invalidate_inodes whose
-sole job is to invalidate the dentries for all inodes related to a
-root. This is in fact wrong and insufficient since such delalloc inodes
-will likely have pending pages or ordered-extents and will be linked to
-the sb->s_inode_list. This means that unmounting a btrfs instance with
-an aborted transaction could potentially lead inodes/their pages
-visible to the system long after their superblock has been freed. This
-in turn leads to a "use-after-free" situation once page shrink is
-triggered. This situation could be simulated by running generic/019
-which would cause such inodes to be left hanging, followed by
-generic/176 which causes memory pressure and page eviction which lead
-to touching the freed super block instance. This situation is
-additionally detected by the unmount code of VFS with the following
-message:
-
-"VFS: Busy inodes after unmount of Self-destruct in 5 seconds.  Have a nice day..."
-
-Additionally btrfs hits WARN_ON(!RB_EMPTY_ROOT(&root->inode_tree));
-in free_fs_root for the same reason.
-
-This patch aims to rectify the sitaution by doing the following:
-
-1. Change btrfs_destroy_delalloc_inodes so that it calls
-invalidate_inode_pages2 for every inode on the delalloc list, this
-ensures that all the pages of the inode are released. This function
-boils down to calling btrfs_releasepage. During test I observed cases
-where inodes on the delalloc list were having an i_count of 0, so this
-necessitates using igrab to be sure we are working on a non-freed inode.
-
-2. Since calling btrfs_releasepage might queue delayed iputs move the
-call out to btrfs_cleanup_transaction in btrfs_error_commit_super before
-calling run_delayed_iputs for the last time. This is necessary to ensure
-that delayed iputs are run.
-
-Note: this patch is tagged for 4.14 stable but the fix applies to older
-versions too but needs to be backported manually due to conflicts.
-
-CC: stable@vger.kernel.org # 4.14.x: 2b8773313494: btrfs: Split btrfs_del_delalloc_inode into 2 functions
-CC: stable@vger.kernel.org # 4.14.x
-Signed-off-by: Nikolay Borisov <nborisov@suse.com>
-Reviewed-by: David Sterba <dsterba@suse.com>
-[ add comment to igrab ]
-Signed-off-by: David Sterba <dsterba@suse.com>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-
----
- fs/btrfs/disk-io.c |   26 +++++++++++++++-----------
- 1 file changed, 15 insertions(+), 11 deletions(-)
-
---- a/fs/btrfs/disk-io.c
-+++ b/fs/btrfs/disk-io.c
-@@ -3744,6 +3744,7 @@ void close_ctree(struct btrfs_fs_info *f
-       set_bit(BTRFS_FS_CLOSING_DONE, &fs_info->flags);
-       btrfs_free_qgroup_config(fs_info);
-+      ASSERT(list_empty(&fs_info->delalloc_roots));
-       if (percpu_counter_sum(&fs_info->delalloc_bytes)) {
-               btrfs_info(fs_info, "at unmount delalloc count %lld",
-@@ -4049,15 +4050,15 @@ static int btrfs_check_super_valid(struc
- static void btrfs_error_commit_super(struct btrfs_fs_info *fs_info)
- {
-+      /* cleanup FS via transaction */
-+      btrfs_cleanup_transaction(fs_info);
-+
-       mutex_lock(&fs_info->cleaner_mutex);
-       btrfs_run_delayed_iputs(fs_info);
-       mutex_unlock(&fs_info->cleaner_mutex);
-       down_write(&fs_info->cleanup_work_sem);
-       up_write(&fs_info->cleanup_work_sem);
--
--      /* cleanup FS via transaction */
--      btrfs_cleanup_transaction(fs_info);
- }
- static void btrfs_destroy_ordered_extents(struct btrfs_root *root)
-@@ -4182,19 +4183,23 @@ static void btrfs_destroy_delalloc_inode
-       list_splice_init(&root->delalloc_inodes, &splice);
-       while (!list_empty(&splice)) {
-+              struct inode *inode = NULL;
-               btrfs_inode = list_first_entry(&splice, struct btrfs_inode,
-                                              delalloc_inodes);
--
--              list_del_init(&btrfs_inode->delalloc_inodes);
--              clear_bit(BTRFS_INODE_IN_DELALLOC_LIST,
--                        &btrfs_inode->runtime_flags);
-+              __btrfs_del_delalloc_inode(root, btrfs_inode);
-               spin_unlock(&root->delalloc_lock);
--              btrfs_invalidate_inodes(btrfs_inode->root);
--
-+              /*
-+               * Make sure we get a live inode and that it'll not disappear
-+               * meanwhile.
-+               */
-+              inode = igrab(&btrfs_inode->vfs_inode);
-+              if (inode) {
-+                      invalidate_inode_pages2(inode->i_mapping);
-+                      iput(inode);
-+              }
-               spin_lock(&root->delalloc_lock);
-       }
--
-       spin_unlock(&root->delalloc_lock);
- }
-@@ -4210,7 +4215,6 @@ static void btrfs_destroy_all_delalloc_i
-       while (!list_empty(&splice)) {
-               root = list_first_entry(&splice, struct btrfs_root,
-                                        delalloc_root);
--              list_del_init(&root->delalloc_root);
-               root = btrfs_grab_fs_root(root);
-               BUG_ON(!root);
-               spin_unlock(&fs_info->delalloc_root_lock);
index b72f836aa0a1a5e5604c337104f73c1cbfb183e5..066ff25d7804c275ba69a5ce112e39d435f80351 100644 (file)
@@ -52,7 +52,6 @@ tick-broadcast-use-for_each_cpu-specially-on-up-kernels.patch
 arm-8769-1-kprobes-fix-to-use-get_kprobe_ctlblk-after-irq-disabed.patch
 arm-8770-1-kprobes-prohibit-probing-on-optimized_callback.patch
 arm-8772-1-kprobes-prohibit-kprobes-on-get_user-functions.patch
-btrfs-fix-delalloc-inodes-invalidation-during-transaction-abort.patch
 btrfs-fix-xattr-loss-after-power-failure.patch
 btrfs-send-fix-invalid-access-to-commit-roots-due-to-concurrent-snapshotting.patch
 btrfs-property-set-incompat-flag-if-lzo-zstd-compression-is-set.patch
diff --git a/queue-4.4/btrfs-send-fix-invalid-access-to-commit-roots-due-to-concurrent-snapshotting.patch b/queue-4.4/btrfs-send-fix-invalid-access-to-commit-roots-due-to-concurrent-snapshotting.patch
deleted file mode 100644 (file)
index 5053fe8..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-From 6f2f0b394b54e2b159ef969a0b5274e9bbf82ff2 Mon Sep 17 00:00:00 2001
-From: Robbie Ko <robbieko@synology.com>
-Date: Mon, 14 May 2018 10:51:34 +0800
-Subject: Btrfs: send, fix invalid access to commit roots due to concurrent snapshotting
-
-From: Robbie Ko <robbieko@synology.com>
-
-commit 6f2f0b394b54e2b159ef969a0b5274e9bbf82ff2 upstream.
-
-[BUG]
-btrfs incremental send BUG happens when creating a snapshot of snapshot
-that is being used by send.
-
-[REASON]
-The problem can happen if while we are doing a send one of the snapshots
-used (parent or send) is snapshotted, because snapshoting implies COWing
-the root of the source subvolume/snapshot.
-
-1. When doing an incremental send, the send process will get the commit
-   roots from the parent and send snapshots, and add references to them
-   through extent_buffer_get().
-
-2. When a snapshot/subvolume is snapshotted, its root node is COWed
-   (transaction.c:create_pending_snapshot()).
-
-3. COWing releases the space used by the node immediately, through:
-
-   __btrfs_cow_block()
-   --btrfs_free_tree_block()
-   ----btrfs_add_free_space(bytenr of node)
-
-4. Because send doesn't hold a transaction open, it's possible that
-   the transaction used to create the snapshot commits, switches the
-   commit root and the old space used by the previous root node gets
-   assigned to some other node allocation. Allocation of a new node will
-   use the existing extent buffer found in memory, which we previously
-   got a reference through extent_buffer_get(), and allow the extent
-   buffer's content (pages) to be modified:
-
-   btrfs_alloc_tree_block
-   --btrfs_reserve_extent
-   ----find_free_extent (get bytenr of old node)
-   --btrfs_init_new_buffer (use bytenr of old node)
-   ----btrfs_find_create_tree_block
-   ------alloc_extent_buffer
-   --------find_extent_buffer (get old node)
-
-5. So send can access invalid memory content and have unpredictable
-   behaviour.
-
-[FIX]
-So we fix the problem by copying the commit roots of the send and
-parent snapshots and use those copies.
-
-CallTrace looks like this:
- ------------[ cut here ]------------
- kernel BUG at fs/btrfs/ctree.c:1861!
- invalid opcode: 0000 [#1] SMP
- CPU: 6 PID: 24235 Comm: btrfs Tainted: P           O 3.10.105 #23721
- ffff88046652d680 ti: ffff88041b720000 task.ti: ffff88041b720000
- RIP: 0010:[<ffffffffa08dd0e8>] read_node_slot+0x108/0x110 [btrfs]
- RSP: 0018:ffff88041b723b68  EFLAGS: 00010246
- RAX: ffff88043ca6b000 RBX: ffff88041b723c50 RCX: ffff880000000000
- RDX: 000000000000004c RSI: ffff880314b133f8 RDI: ffff880458b24000
- RBP: 0000000000000000 R08: 0000000000000001 R09: ffff88041b723c66
- R10: 0000000000000001 R11: 0000000000001000 R12: ffff8803f3e48890
- R13: ffff8803f3e48880 R14: ffff880466351800 R15: 0000000000000001
- FS:  00007f8c321dc8c0(0000) GS:ffff88047fcc0000(0000)
- CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
- R2: 00007efd1006d000 CR3: 0000000213a24000 CR4: 00000000003407e0
- DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
- DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
- Stack:
- ffff88041b723c50 ffff8803f3e48880 ffff8803f3e48890 ffff8803f3e48880
- ffff880466351800 0000000000000001 ffffffffa08dd9d7 ffff88041b723c50
- ffff8803f3e48880 ffff88041b723c66 ffffffffa08dde85 a9ff88042d2c4400
- Call Trace:
- [<ffffffffa08dd9d7>] ? tree_move_down.isra.33+0x27/0x50 [btrfs]
- [<ffffffffa08dde85>] ? tree_advance+0xb5/0xc0 [btrfs]
- [<ffffffffa08e83d4>] ? btrfs_compare_trees+0x2d4/0x760 [btrfs]
- [<ffffffffa0982050>] ? finish_inode_if_needed+0x870/0x870 [btrfs]
- [<ffffffffa09841ea>] ? btrfs_ioctl_send+0xeda/0x1050 [btrfs]
- [<ffffffffa094bd3d>] ? btrfs_ioctl+0x1e3d/0x33f0 [btrfs]
- [<ffffffff81111133>] ? handle_pte_fault+0x373/0x990
- [<ffffffff8153a096>] ? atomic_notifier_call_chain+0x16/0x20
- [<ffffffff81063256>] ? set_task_cpu+0xb6/0x1d0
- [<ffffffff811122c3>] ? handle_mm_fault+0x143/0x2a0
- [<ffffffff81539cc0>] ? __do_page_fault+0x1d0/0x500
- [<ffffffff81062f07>] ? check_preempt_curr+0x57/0x90
- [<ffffffff8115075a>] ? do_vfs_ioctl+0x4aa/0x990
- [<ffffffff81034f83>] ? do_fork+0x113/0x3b0
- [<ffffffff812dd7d7>] ? trace_hardirqs_off_thunk+0x3a/0x6c
- [<ffffffff81150cc8>] ? SyS_ioctl+0x88/0xa0
- [<ffffffff8153e422>] ? system_call_fastpath+0x16/0x1b
- ---[ end trace 29576629ee80b2e1 ]---
-
-Fixes: 7069830a9e38 ("Btrfs: add btrfs_compare_trees function")
-CC: stable@vger.kernel.org # 3.6+
-Signed-off-by: Robbie Ko <robbieko@synology.com>
-Reviewed-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/ctree.c |   16 ++++++++++++++--
- 1 file changed, 14 insertions(+), 2 deletions(-)
-
---- a/fs/btrfs/ctree.c
-+++ b/fs/btrfs/ctree.c
-@@ -5415,12 +5415,24 @@ int btrfs_compare_trees(struct btrfs_roo
-       down_read(&left_root->fs_info->commit_root_sem);
-       left_level = btrfs_header_level(left_root->commit_root);
-       left_root_level = left_level;
--      left_path->nodes[left_level] = left_root->commit_root;
-+      left_path->nodes[left_level] =
-+                      btrfs_clone_extent_buffer(left_root->commit_root);
-+      if (!left_path->nodes[left_level]) {
-+              up_read(&fs_info->commit_root_sem);
-+              ret = -ENOMEM;
-+              goto out;
-+      }
-       extent_buffer_get(left_path->nodes[left_level]);
-       right_level = btrfs_header_level(right_root->commit_root);
-       right_root_level = right_level;
--      right_path->nodes[right_level] = right_root->commit_root;
-+      right_path->nodes[right_level] =
-+                      btrfs_clone_extent_buffer(right_root->commit_root);
-+      if (!right_path->nodes[right_level]) {
-+              up_read(&fs_info->commit_root_sem);
-+              ret = -ENOMEM;
-+              goto out;
-+      }
-       extent_buffer_get(right_path->nodes[right_level]);
-       up_read(&left_root->fs_info->commit_root_sem);
index 5eb08a9c0ce510b991ba548f7cb787591d3a8ce1..01196a328070815147539004d7d5afd91a0f89b6 100644 (file)
@@ -66,5 +66,4 @@ arm-8769-1-kprobes-fix-to-use-get_kprobe_ctlblk-after-irq-disabed.patch
 arm-8770-1-kprobes-prohibit-probing-on-optimized_callback.patch
 arm-8772-1-kprobes-prohibit-kprobes-on-get_user-functions.patch
 btrfs-fix-xattr-loss-after-power-failure.patch
-btrfs-send-fix-invalid-access-to-commit-roots-due-to-concurrent-snapshotting.patch
 btrfs-fix-crash-when-trying-to-resume-balance-without-the-resume-flag.patch
diff --git a/queue-4.9/btrfs-send-fix-invalid-access-to-commit-roots-due-to-concurrent-snapshotting.patch b/queue-4.9/btrfs-send-fix-invalid-access-to-commit-roots-due-to-concurrent-snapshotting.patch
deleted file mode 100644 (file)
index f2b8429..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-From 6f2f0b394b54e2b159ef969a0b5274e9bbf82ff2 Mon Sep 17 00:00:00 2001
-From: Robbie Ko <robbieko@synology.com>
-Date: Mon, 14 May 2018 10:51:34 +0800
-Subject: Btrfs: send, fix invalid access to commit roots due to concurrent snapshotting
-
-From: Robbie Ko <robbieko@synology.com>
-
-commit 6f2f0b394b54e2b159ef969a0b5274e9bbf82ff2 upstream.
-
-[BUG]
-btrfs incremental send BUG happens when creating a snapshot of snapshot
-that is being used by send.
-
-[REASON]
-The problem can happen if while we are doing a send one of the snapshots
-used (parent or send) is snapshotted, because snapshoting implies COWing
-the root of the source subvolume/snapshot.
-
-1. When doing an incremental send, the send process will get the commit
-   roots from the parent and send snapshots, and add references to them
-   through extent_buffer_get().
-
-2. When a snapshot/subvolume is snapshotted, its root node is COWed
-   (transaction.c:create_pending_snapshot()).
-
-3. COWing releases the space used by the node immediately, through:
-
-   __btrfs_cow_block()
-   --btrfs_free_tree_block()
-   ----btrfs_add_free_space(bytenr of node)
-
-4. Because send doesn't hold a transaction open, it's possible that
-   the transaction used to create the snapshot commits, switches the
-   commit root and the old space used by the previous root node gets
-   assigned to some other node allocation. Allocation of a new node will
-   use the existing extent buffer found in memory, which we previously
-   got a reference through extent_buffer_get(), and allow the extent
-   buffer's content (pages) to be modified:
-
-   btrfs_alloc_tree_block
-   --btrfs_reserve_extent
-   ----find_free_extent (get bytenr of old node)
-   --btrfs_init_new_buffer (use bytenr of old node)
-   ----btrfs_find_create_tree_block
-   ------alloc_extent_buffer
-   --------find_extent_buffer (get old node)
-
-5. So send can access invalid memory content and have unpredictable
-   behaviour.
-
-[FIX]
-So we fix the problem by copying the commit roots of the send and
-parent snapshots and use those copies.
-
-CallTrace looks like this:
- ------------[ cut here ]------------
- kernel BUG at fs/btrfs/ctree.c:1861!
- invalid opcode: 0000 [#1] SMP
- CPU: 6 PID: 24235 Comm: btrfs Tainted: P           O 3.10.105 #23721
- ffff88046652d680 ti: ffff88041b720000 task.ti: ffff88041b720000
- RIP: 0010:[<ffffffffa08dd0e8>] read_node_slot+0x108/0x110 [btrfs]
- RSP: 0018:ffff88041b723b68  EFLAGS: 00010246
- RAX: ffff88043ca6b000 RBX: ffff88041b723c50 RCX: ffff880000000000
- RDX: 000000000000004c RSI: ffff880314b133f8 RDI: ffff880458b24000
- RBP: 0000000000000000 R08: 0000000000000001 R09: ffff88041b723c66
- R10: 0000000000000001 R11: 0000000000001000 R12: ffff8803f3e48890
- R13: ffff8803f3e48880 R14: ffff880466351800 R15: 0000000000000001
- FS:  00007f8c321dc8c0(0000) GS:ffff88047fcc0000(0000)
- CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
- R2: 00007efd1006d000 CR3: 0000000213a24000 CR4: 00000000003407e0
- DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
- DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
- Stack:
- ffff88041b723c50 ffff8803f3e48880 ffff8803f3e48890 ffff8803f3e48880
- ffff880466351800 0000000000000001 ffffffffa08dd9d7 ffff88041b723c50
- ffff8803f3e48880 ffff88041b723c66 ffffffffa08dde85 a9ff88042d2c4400
- Call Trace:
- [<ffffffffa08dd9d7>] ? tree_move_down.isra.33+0x27/0x50 [btrfs]
- [<ffffffffa08dde85>] ? tree_advance+0xb5/0xc0 [btrfs]
- [<ffffffffa08e83d4>] ? btrfs_compare_trees+0x2d4/0x760 [btrfs]
- [<ffffffffa0982050>] ? finish_inode_if_needed+0x870/0x870 [btrfs]
- [<ffffffffa09841ea>] ? btrfs_ioctl_send+0xeda/0x1050 [btrfs]
- [<ffffffffa094bd3d>] ? btrfs_ioctl+0x1e3d/0x33f0 [btrfs]
- [<ffffffff81111133>] ? handle_pte_fault+0x373/0x990
- [<ffffffff8153a096>] ? atomic_notifier_call_chain+0x16/0x20
- [<ffffffff81063256>] ? set_task_cpu+0xb6/0x1d0
- [<ffffffff811122c3>] ? handle_mm_fault+0x143/0x2a0
- [<ffffffff81539cc0>] ? __do_page_fault+0x1d0/0x500
- [<ffffffff81062f07>] ? check_preempt_curr+0x57/0x90
- [<ffffffff8115075a>] ? do_vfs_ioctl+0x4aa/0x990
- [<ffffffff81034f83>] ? do_fork+0x113/0x3b0
- [<ffffffff812dd7d7>] ? trace_hardirqs_off_thunk+0x3a/0x6c
- [<ffffffff81150cc8>] ? SyS_ioctl+0x88/0xa0
- [<ffffffff8153e422>] ? system_call_fastpath+0x16/0x1b
- ---[ end trace 29576629ee80b2e1 ]---
-
-Fixes: 7069830a9e38 ("Btrfs: add btrfs_compare_trees function")
-CC: stable@vger.kernel.org # 3.6+
-Signed-off-by: Robbie Ko <robbieko@synology.com>
-Reviewed-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/ctree.c |   16 ++++++++++++++--
- 1 file changed, 14 insertions(+), 2 deletions(-)
-
---- a/fs/btrfs/ctree.c
-+++ b/fs/btrfs/ctree.c
-@@ -5433,12 +5433,24 @@ int btrfs_compare_trees(struct btrfs_roo
-       down_read(&left_root->fs_info->commit_root_sem);
-       left_level = btrfs_header_level(left_root->commit_root);
-       left_root_level = left_level;
--      left_path->nodes[left_level] = left_root->commit_root;
-+      left_path->nodes[left_level] =
-+                      btrfs_clone_extent_buffer(left_root->commit_root);
-+      if (!left_path->nodes[left_level]) {
-+              up_read(&fs_info->commit_root_sem);
-+              ret = -ENOMEM;
-+              goto out;
-+      }
-       extent_buffer_get(left_path->nodes[left_level]);
-       right_level = btrfs_header_level(right_root->commit_root);
-       right_root_level = right_level;
--      right_path->nodes[right_level] = right_root->commit_root;
-+      right_path->nodes[right_level] =
-+                      btrfs_clone_extent_buffer(right_root->commit_root);
-+      if (!right_path->nodes[right_level]) {
-+              up_read(&fs_info->commit_root_sem);
-+              ret = -ENOMEM;
-+              goto out;
-+      }
-       extent_buffer_get(right_path->nodes[right_level]);
-       up_read(&left_root->fs_info->commit_root_sem);
index 50756d677c119ff1d13a7f767d884dba768ea455..18aa731d98cd473c000dad29260aa035b7b6cce1 100644 (file)
@@ -30,5 +30,4 @@ arm-8769-1-kprobes-fix-to-use-get_kprobe_ctlblk-after-irq-disabed.patch
 arm-8770-1-kprobes-prohibit-probing-on-optimized_callback.patch
 arm-8772-1-kprobes-prohibit-kprobes-on-get_user-functions.patch
 btrfs-fix-xattr-loss-after-power-failure.patch
-btrfs-send-fix-invalid-access-to-commit-roots-due-to-concurrent-snapshotting.patch
 btrfs-fix-crash-when-trying-to-resume-balance-without-the-resume-flag.patch