/* clone data */
        key.objectid = btrfs_ino(src);
        key.type = BTRFS_EXTENT_DATA_KEY;
-       key.offset = 0;
+       key.offset = off;
 
        while (1) {
                /*
                                0, 0);
                if (ret < 0)
                        goto out;
+               /*
+                * First search, if no extent item that starts at offset off was
+                * found but the previous item is an extent item, it's possible
+                * it might overlap our target range, therefore process it.
+                */
+               if (key.offset == off && ret > 0 && path->slots[0] > 0) {
+                       btrfs_item_key_to_cpu(path->nodes[0], &key,
+                                             path->slots[0] - 1);
+                       if (key.type == BTRFS_EXTENT_DATA_KEY)
+                               path->slots[0]--;
+               }
 
                nritems = btrfs_header_nritems(path->nodes[0]);
 process_slot:
                                                                    extent);
                        }
 
-                       if (key.offset + datal <= off ||
-                           key.offset >= off + len - 1) {
+                       /*
+                        * The first search might have left us at an extent
+                        * item that ends before our target range's start, can
+                        * happen if we have holes and NO_HOLES feature enabled.
+                        */
+                       if (key.offset + datal <= off) {
                                path->slots[0]++;
                                goto process_slot;
+                       } else if (key.offset >= off + len) {
+                               break;
                        }
 
                        size = btrfs_item_size_nr(leaf, slot);
                                goto out;
                        }
                        ret = btrfs_end_transaction(trans, root);
+                       if (new_key.offset + datal >= destoff + len)
+                               break;
                }
                btrfs_release_path(path);
                key.offset++;
        ret = 0;
 
 out:
-       btrfs_release_path(path);
        btrfs_free_path(path);
        vfree(buf);
        return ret;