struct bio *bio, u64 file_start, int contig);
 int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
                             struct list_head *list, int search_commit);
+void btrfs_extent_item_to_extent_map(struct inode *inode,
+                                    const struct btrfs_path *path,
+                                    struct btrfs_file_extent_item *fi,
+                                    const bool new_inline,
+                                    struct extent_map *em);
+
 /* inode.c */
 struct btrfs_delalloc_work {
        struct inode *inode;
 
 fail_unlock:
        goto out;
 }
+
+void btrfs_extent_item_to_extent_map(struct inode *inode,
+                                    const struct btrfs_path *path,
+                                    struct btrfs_file_extent_item *fi,
+                                    const bool new_inline,
+                                    struct extent_map *em)
+{
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       struct extent_buffer *leaf = path->nodes[0];
+       const int slot = path->slots[0];
+       struct btrfs_key key;
+       u64 extent_start, extent_end;
+       u64 bytenr;
+       u8 type = btrfs_file_extent_type(leaf, fi);
+       int compress_type = btrfs_file_extent_compression(leaf, fi);
+
+       em->bdev = root->fs_info->fs_devices->latest_bdev;
+       btrfs_item_key_to_cpu(leaf, &key, slot);
+       extent_start = key.offset;
+
+       if (type == BTRFS_FILE_EXTENT_REG ||
+           type == BTRFS_FILE_EXTENT_PREALLOC) {
+               extent_end = extent_start +
+                       btrfs_file_extent_num_bytes(leaf, fi);
+       } else if (type == BTRFS_FILE_EXTENT_INLINE) {
+               size_t size;
+               size = btrfs_file_extent_inline_len(leaf, slot, fi);
+               extent_end = ALIGN(extent_start + size, root->sectorsize);
+       }
+
+       em->ram_bytes = btrfs_file_extent_ram_bytes(leaf, fi);
+       if (type == BTRFS_FILE_EXTENT_REG ||
+           type == BTRFS_FILE_EXTENT_PREALLOC) {
+               em->start = extent_start;
+               em->len = extent_end - extent_start;
+               em->orig_start = extent_start -
+                       btrfs_file_extent_offset(leaf, fi);
+               em->orig_block_len = btrfs_file_extent_disk_num_bytes(leaf, fi);
+               bytenr = btrfs_file_extent_disk_bytenr(leaf, fi);
+               if (bytenr == 0) {
+                       em->block_start = EXTENT_MAP_HOLE;
+                       return;
+               }
+               if (compress_type != BTRFS_COMPRESS_NONE) {
+                       set_bit(EXTENT_FLAG_COMPRESSED, &em->flags);
+                       em->compress_type = compress_type;
+                       em->block_start = bytenr;
+                       em->block_len = em->orig_block_len;
+               } else {
+                       bytenr += btrfs_file_extent_offset(leaf, fi);
+                       em->block_start = bytenr;
+                       em->block_len = em->len;
+                       if (type == BTRFS_FILE_EXTENT_PREALLOC)
+                               set_bit(EXTENT_FLAG_PREALLOC, &em->flags);
+               }
+       } else if (type == BTRFS_FILE_EXTENT_INLINE) {
+               em->block_start = EXTENT_MAP_INLINE;
+               em->start = extent_start;
+               em->len = extent_end - extent_start;
+               /*
+                * Initialize orig_start and block_len with the same values
+                * as in inode.c:btrfs_get_extent().
+                */
+               em->orig_start = EXTENT_MAP_HOLE;
+               em->block_len = (u64)-1;
+               if (!new_inline && compress_type != BTRFS_COMPRESS_NONE) {
+                       set_bit(EXTENT_FLAG_COMPRESSED, &em->flags);
+                       em->compress_type = compress_type;
+               }
+       } else {
+               btrfs_err(root->fs_info,
+                         "unknown file extent item type %d, inode %llu, offset %llu, root %llu",
+                         type, btrfs_ino(inode), extent_start,
+                         root->root_key.objectid);
+       }
+}
 
 {
        int ret;
        int err = 0;
-       u64 bytenr;
        u64 extent_start = 0;
        u64 extent_end = 0;
        u64 objectid = btrfs_ino(inode);
        struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
        struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
        struct btrfs_trans_handle *trans = NULL;
-       int compress_type;
+       const bool new_inline = !page || create;
 
 again:
        read_lock(&em_tree->lock);
 
        found_type = btrfs_file_extent_type(leaf, item);
        extent_start = found_key.offset;
-       compress_type = btrfs_file_extent_compression(leaf, item);
        if (found_type == BTRFS_FILE_EXTENT_REG ||
            found_type == BTRFS_FILE_EXTENT_PREALLOC) {
                extent_end = extent_start +
                goto not_found_em;
        }
 
-       em->ram_bytes = btrfs_file_extent_ram_bytes(leaf, item);
+       btrfs_extent_item_to_extent_map(inode, path, item, new_inline, em);
+
        if (found_type == BTRFS_FILE_EXTENT_REG ||
            found_type == BTRFS_FILE_EXTENT_PREALLOC) {
-               em->start = extent_start;
-               em->len = extent_end - extent_start;
-               em->orig_start = extent_start -
-                                btrfs_file_extent_offset(leaf, item);
-               em->orig_block_len = btrfs_file_extent_disk_num_bytes(leaf,
-                                                                     item);
-               bytenr = btrfs_file_extent_disk_bytenr(leaf, item);
-               if (bytenr == 0) {
-                       em->block_start = EXTENT_MAP_HOLE;
-                       goto insert;
-               }
-               if (compress_type != BTRFS_COMPRESS_NONE) {
-                       set_bit(EXTENT_FLAG_COMPRESSED, &em->flags);
-                       em->compress_type = compress_type;
-                       em->block_start = bytenr;
-                       em->block_len = em->orig_block_len;
-               } else {
-                       bytenr += btrfs_file_extent_offset(leaf, item);
-                       em->block_start = bytenr;
-                       em->block_len = em->len;
-                       if (found_type == BTRFS_FILE_EXTENT_PREALLOC)
-                               set_bit(EXTENT_FLAG_PREALLOC, &em->flags);
-               }
                goto insert;
        } else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
                unsigned long ptr;
                size_t extent_offset;
                size_t copy_size;
 
-               em->block_start = EXTENT_MAP_INLINE;
-               if (!page || create) {
-                       em->start = extent_start;
-                       em->len = extent_end - extent_start;
+               if (new_inline)
                        goto out;
-               }
 
                size = btrfs_file_extent_inline_len(leaf, path->slots[0], item);
                extent_offset = page_offset(page) + pg_offset - extent_start;
                em->len = ALIGN(copy_size, root->sectorsize);
                em->orig_block_len = em->len;
                em->orig_start = em->start;
-               if (compress_type) {
-                       set_bit(EXTENT_FLAG_COMPRESSED, &em->flags);
-                       em->compress_type = compress_type;
-               }
                ptr = btrfs_file_extent_inline_start(item) + extent_offset;
                if (create == 0 && !PageUptodate(page)) {
                        if (btrfs_file_extent_compression(leaf, item) !=
                set_extent_uptodate(io_tree, em->start,
                                    extent_map_end(em) - 1, NULL, GFP_NOFS);
                goto insert;
-       } else {
-               WARN(1, KERN_ERR "btrfs unknown found_type %d\n", found_type);
        }
 not_found:
        em->start = start;
 
        return ret;
 }
 
+static void clone_update_extent_map(struct inode *inode,
+                                   const struct btrfs_trans_handle *trans,
+                                   const struct btrfs_path *path,
+                                   struct btrfs_file_extent_item *fi,
+                                   const u64 hole_offset,
+                                   const u64 hole_len)
+{
+       struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
+       struct extent_map *em;
+       int ret;
+
+       em = alloc_extent_map();
+       if (!em) {
+               set_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
+                       &BTRFS_I(inode)->runtime_flags);
+               return;
+       }
+
+       if (fi) {
+               btrfs_extent_item_to_extent_map(inode, path, fi, false, em);
+               em->generation = -1;
+               if (btrfs_file_extent_type(path->nodes[0], fi) ==
+                   BTRFS_FILE_EXTENT_INLINE)
+                       set_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
+                               &BTRFS_I(inode)->runtime_flags);
+       } else {
+               em->start = hole_offset;
+               em->len = hole_len;
+               em->ram_bytes = em->len;
+               em->orig_start = hole_offset;
+               em->block_start = EXTENT_MAP_HOLE;
+               em->block_len = 0;
+               em->orig_block_len = 0;
+               em->compress_type = BTRFS_COMPRESS_NONE;
+               em->generation = trans->transid;
+       }
+
+       while (1) {
+               write_lock(&em_tree->lock);
+               ret = add_extent_mapping(em_tree, em, 1);
+               write_unlock(&em_tree->lock);
+               if (ret != -EEXIST) {
+                       free_extent_map(em);
+                       break;
+               }
+               btrfs_drop_extent_cache(inode, em->start,
+                                       em->start + em->len - 1, 0);
+       }
+
+       if (unlikely(ret))
+               set_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
+                       &BTRFS_I(inode)->runtime_flags);
+}
+
 /**
  * btrfs_clone() - clone a range from inode file to another
  *
                                            btrfs_item_ptr_offset(leaf, slot),
                                            size);
                                inode_add_bytes(inode, datal);
+                               extent = btrfs_item_ptr(leaf, slot,
+                                               struct btrfs_file_extent_item);
                        }
 
+                       /* If we have an implicit hole (NO_HOLES feature). */
+                       if (drop_start < new_key.offset)
+                               clone_update_extent_map(inode, trans,
+                                               path, NULL, drop_start,
+                                               new_key.offset - drop_start);
+
+                       clone_update_extent_map(inode, trans, path,
+                                               extent, 0, 0);
+
                        btrfs_mark_buffer_dirty(leaf);
                        btrfs_release_path(path);
 
                }
                ret = clone_finish_inode_update(trans, inode, destoff + len,
                                                destoff, olen);
+               if (ret)
+                       goto out;
+               clone_update_extent_map(inode, trans, path, NULL, last_dest_end,
+                                       destoff + len - last_dest_end);
        }
 
 out: