Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi...
[platform/kernel/linux-exynos.git] / fs / btrfs / send.c
index b082210..8f1d3d6 100644 (file)
@@ -4733,7 +4733,7 @@ static ssize_t fill_read_buf(struct send_ctx *sctx, u64 offset, u32 len)
        /* initial readahead */
        memset(&sctx->ra, 0, sizeof(struct file_ra_state));
        file_ra_state_init(&sctx->ra, inode->i_mapping);
-       btrfs_force_ra(inode->i_mapping, &sctx->ra, NULL, index,
+       page_cache_sync_readahead(inode->i_mapping, &sctx->ra, NULL, index,
                       last_index - index + 1);
 
        while (index <= last_index) {
@@ -4992,6 +4992,25 @@ static int clone_range(struct send_ctx *sctx,
        struct btrfs_key key;
        int ret;
 
+       /*
+        * Prevent cloning from a zero offset with a length matching the sector
+        * size because in some scenarios this will make the receiver fail.
+        *
+        * For example, if in the source filesystem the extent at offset 0
+        * has a length of sectorsize and it was written using direct IO, then
+        * it can never be an inline extent (even if compression is enabled).
+        * Then this extent can be cloned in the original filesystem to a non
+        * zero file offset, but it may not be possible to clone in the
+        * destination filesystem because it can be inlined due to compression
+        * on the destination filesystem (as the receiver's write operations are
+        * always done using buffered IO). The same happens when the original
+        * filesystem does not have compression enabled but the destination
+        * filesystem has.
+        */
+       if (clone_root->offset == 0 &&
+           len == sctx->send_root->fs_info->sectorsize)
+               return send_extent_data(sctx, offset, len);
+
        path = alloc_path_for_send();
        if (!path)
                return -ENOMEM;