|
@@ -3020,7 +3020,7 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
|
|
|
/* clone data */
|
|
|
key.objectid = btrfs_ino(src);
|
|
|
key.type = BTRFS_EXTENT_DATA_KEY;
|
|
|
- key.offset = 0;
|
|
|
+ key.offset = off;
|
|
|
|
|
|
while (1) {
|
|
|
/*
|
|
@@ -3032,6 +3032,17 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
|
|
|
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:
|
|
@@ -3081,10 +3092,16 @@ 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);
|
|
@@ -3291,6 +3308,8 @@ process_slot:
|
|
|
goto out;
|
|
|
}
|
|
|
ret = btrfs_end_transaction(trans, root);
|
|
|
+ if (new_key.offset + datal >= destoff + len)
|
|
|
+ break;
|
|
|
}
|
|
|
btrfs_release_path(path);
|
|
|
key.offset++;
|
|
@@ -3298,7 +3317,6 @@ process_slot:
|
|
|
ret = 0;
|
|
|
|
|
|
out:
|
|
|
- btrfs_release_path(path);
|
|
|
btrfs_free_path(path);
|
|
|
vfree(buf);
|
|
|
return ret;
|