Home Home > GIT Browse > SLE15-AZURE
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
commit64bec9fcaa2719cde1311ed871ea1811cf3016a5 (patch)
tree41e93c4646022ed12024dcd3967c40c0a7b725ed
parent3cc6bc7ac06a5fdb4e76d1e702795ecd6a81d9e1 (diff)
Btrfs: send, flush dellaloc in order to avoid data loss
(bsc#1133320). suse-commit: 9e6fc7e1ea30fb7f03a76a818b884770e8d4d87b
-rw-r--r--fs/btrfs/send.c36
1 files changed, 36 insertions, 0 deletions
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 @@ commit_trans:
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;