Home Home > GIT Browse > SLE12-SP4
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilipe Manana <fdmanana@suse.com>2019-05-21 11:44:50 +0100
committerFilipe Manana <fdmanana@suse.com>2019-05-21 11:44:50 +0100
commit9e6fc7e1ea30fb7f03a76a818b884770e8d4d87b (patch)
tree36be26b87bc7e7ba5686e071dc4697009fd2c3ab
parentf1cd52b27711538b6c3d081325198f6e63e8de8a (diff)
Btrfs: send, flush dellaloc in order to avoid data loss
(bsc#1133320).
-rw-r--r--patches.suse/btrfs-send-flush-dellaloc-in-order-to-avoid-data-los.patch136
-rw-r--r--series.conf1
2 files changed, 137 insertions, 0 deletions
diff --git a/patches.suse/btrfs-send-flush-dellaloc-in-order-to-avoid-data-los.patch b/patches.suse/btrfs-send-flush-dellaloc-in-order-to-avoid-data-los.patch
new file mode 100644
index 0000000000..08bae44eec
--- /dev/null
+++ b/patches.suse/btrfs-send-flush-dellaloc-in-order-to-avoid-data-los.patch
@@ -0,0 +1,136 @@
+From: Filipe Manana <fdmanana@suse.com>
+Date: Mon, 15 Apr 2019 09:29:36 +0100
+Git-commit: 9f89d5de8631c7930898a601b6612e271aa2261c
+Patch-mainline: 5.2-rc1
+References: bsc#1133320
+Subject: [PATCH] Btrfs: send, flush dellaloc in order to avoid data loss
+
+When we set a subvolume to read-only mode we do not flush dellaloc for any
+of its inodes (except if the filesystem is mounted with -o flushoncommit),
+since it does not affect correctness for any subsequent operations - except
+for a future send operation. The send operation will not be able to see the
+delalloc data since the respective file extent items, inode item updates,
+backreferences, etc, have not hit yet the subvolume and extent trees.
+
+Effectively this means data loss, since the send stream will not contain
+any data from existing delalloc. Another problem from this is that if the
+writeback starts and finishes while the send operation is in progress, we
+have the subvolume tree being being modified concurrently which can result
+in send failing unexpectedly with EIO or hitting runtime errors, assertion
+failures or hitting BUG_ONs, etc.
+
+Simple reproducer:
+
+ $ mkfs.btrfs -f /dev/sdb
+ $ mount /dev/sdb /mnt
+
+ $ btrfs subvolume create /mnt/sv
+ $ xfs_io -f -c "pwrite -S 0xea 0 108K" /mnt/sv/foo
+
+ $ btrfs property set /mnt/sv ro true
+ $ btrfs send -f /tmp/send.stream /mnt/sv
+
+ $ od -t x1 -A d /mnt/sv/foo
+ 0000000 ea ea ea ea ea ea ea ea ea ea ea ea ea ea ea ea
+ *
+ 0110592
+
+ $ umount /mnt
+ $ mkfs.btrfs -f /dev/sdc
+ $ mount /dev/sdc /mnt
+
+ $ btrfs receive -f /tmp/send.stream /mnt
+ $ echo $?
+ 0
+ $ od -t x1 -A d /mnt/sv/foo
+ 0000000
+ # ---> empty file
+
+Since this a problem that affects send only, fix it in send by flushing
+dellaloc for all the roots used by the send operation before send starts
+to process the commit roots.
+
+This is a problem that affects send since it was introduced (commit
+31db9f7c23fbf7 ("Btrfs: introduce BTRFS_IOC_SEND for btrfs send/receive"))
+but backporting it to older kernels has some dependencies:
+
+- For kernels between 3.19 and 4.20, it depends on commit 3cd24c698004d2
+ ("btrfs: use tagged writepage to mitigate livelock of snapshot") because
+ the function btrfs_start_delalloc_snapshot() does not exist before that
+ commit. So one has to either pick that commit or replace the calls to
+ btrfs_start_delalloc_snapshot() in this patch with calls to
+ btrfs_start_delalloc_inodes().
+
+- For kernels older than 3.19 it also requires commit e5fa8f865b3324
+ ("Btrfs: ensure send always works on roots without orphans") because
+ it depends on the function ensure_commit_roots_uptodate() which that
+ commits introduced.
+
+- No dependencies for 5.0+ kernels.
+
+A test case for fstests follows soon.
+
+CC: stable@vger.kernel.org # 3.19+
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+---
+ fs/btrfs/send.c | 36 ++++++++++++++++++++++++++++++++++++
+ 1 file changed, 36 insertions(+)
+
+diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
+index b1eba0274983..0cfad0b15c4e 100644
+--- a/fs/btrfs/send.c
++++ b/fs/btrfs/send.c
+@@ -6574,6 +6574,38 @@ static int ensure_commit_roots_uptodate(struct send_ctx *sctx)
+ return btrfs_commit_transaction(trans);
+ }
+
++/*
++ * Make sure any existing dellaloc is flushed for any root used by a send
++ * operation so that we do not miss any data and we do not race with writeback
++ * finishing and changing a tree while send is using the tree. This could
++ * happen if a subvolume is in RW mode, has delalloc, is turned to RO mode and
++ * a send operation then uses the subvolume.
++ * After flushing delalloc ensure_commit_roots_uptodate() must be called.
++ */
++static int flush_delalloc_roots(struct send_ctx *sctx)
++{
++ struct btrfs_root *root = sctx->parent_root;
++ int ret;
++ int i;
++
++ if (root) {
++ ret = btrfs_start_delalloc_inodes(root, 0);
++ if (ret)
++ return ret;
++ btrfs_wait_ordered_extents(root, -1, 0, U64_MAX);
++ }
++
++ for (i = 0; i < sctx->clone_roots_cnt; i++) {
++ root = sctx->clone_roots[i].root;
++ ret = btrfs_start_delalloc_inodes(root, 0);
++ if (ret)
++ return ret;
++ btrfs_wait_ordered_extents(root, -1, 0, U64_MAX);
++ }
++
++ return 0;
++}
++
+ static void btrfs_root_dec_send_in_progress(struct btrfs_root* root)
+ {
+ spin_lock(&root->root_item_lock);
+@@ -6809,6 +6841,10 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
+ NULL);
+ sort_clone_roots = 1;
+
++ ret = flush_delalloc_roots(sctx);
++ if (ret)
++ goto out;
++
+ ret = ensure_commit_roots_uptodate(sctx);
+ if (ret)
+ goto out;
+--
+2.19.0
+
diff --git a/series.conf b/series.conf
index d43f83700f..731e2bdfc2 100644
--- a/series.conf
+++ b/series.conf
@@ -21904,6 +21904,7 @@
patches.suse/0007-btrfs-extent-tree-Use-btrfs_ref-to-refactor-btrfs_in.patch
patches.suse/0008-btrfs-extent-tree-Use-btrfs_ref-to-refactor-btrfs_fr.patch
patches.suse/0009-btrfs-qgroup-Don-t-scan-leaf-if-we-re-modifying-relo.patch
+ patches.suse/btrfs-send-flush-dellaloc-in-order-to-avoid-data-los.patch
patches.drivers/mmc-core-fix-possible-use-after-free-of-host.patch
patches.drivers/phy-sun4i-usb-Make-sure-to-disable-PHY0-passby-for-p.patch
patches.drivers/stm-class-Fix-channel-free-in-stm-output-free-path.patch