Skip to content

Commit 11f2069

Browse files
fdmananakdave
authored andcommitted
Btrfs: send, allow clone operations within the same file
For send we currently skip clone operations when the source and destination files are the same. This is so because clone didn't support this case in its early days, but support for it was added back in May 2013 by commit a96fbc7 ("Btrfs: allow file data clone within a file"). This change adds support for it. Example: $ mkfs.btrfs -f /dev/sdd $ mount /dev/sdd /mnt/sdd $ xfs_io -f -c "pwrite -S 0xab -b 64K 0 64K" /mnt/sdd/foobar $ xfs_io -c "reflink /mnt/sdd/foobar 0 64K 64K" /mnt/sdd/foobar $ btrfs subvolume snapshot -r /mnt/sdd /mnt/sdd/snap $ mkfs.btrfs -f /dev/sde $ mount /dev/sde /mnt/sde $ btrfs send /mnt/sdd/snap | btrfs receive /mnt/sde Without this change file foobar at the destination has a single 128Kb extent: $ filefrag -v /mnt/sde/snap/foobar Filesystem type is: 9123683e File size of /mnt/sde/snap/foobar is 131072 (32 blocks of 4096 bytes) ext: logical_offset: physical_offset: length: expected: flags: 0: 0.. 31: 0.. 31: 32: last,unknown_loc,delalloc,eof /mnt/sde/snap/foobar: 1 extent found With this we get a single 64Kb extent that is shared at file offsets 0 and 64K, just like in the source filesystem: $ filefrag -v /mnt/sde/snap/foobar Filesystem type is: 9123683e File size of /mnt/sde/snap/foobar is 131072 (32 blocks of 4096 bytes) ext: logical_offset: physical_offset: length: expected: flags: 0: 0.. 15: 3328.. 3343: 16: shared 1: 16.. 31: 3328.. 3343: 16: 3344: last,shared,eof /mnt/sde/snap/foobar: 2 extents found Reviewed-by: Josef Bacik <[email protected]> Signed-off-by: Filipe Manana <[email protected]> Reviewed-by: David Sterba <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent 6b7faad commit 11f2069

File tree

1 file changed

+13
-5
lines changed

1 file changed

+13
-5
lines changed

fs/btrfs/send.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1248,12 +1248,20 @@ static int __iterate_backrefs(u64 ino, u64 offset, u64 root, void *ctx_)
12481248
*/
12491249
if (found->root == bctx->sctx->send_root) {
12501250
/*
1251-
* TODO for the moment we don't accept clones from the inode
1252-
* that is currently send. We may change this when
1253-
* BTRFS_IOC_CLONE_RANGE supports cloning from and to the same
1254-
* file.
1251+
* If the source inode was not yet processed we can't issue a
1252+
* clone operation, as the source extent does not exist yet at
1253+
* the destination of the stream.
12551254
*/
1256-
if (ino >= bctx->cur_objectid)
1255+
if (ino > bctx->cur_objectid)
1256+
return 0;
1257+
/*
1258+
* We clone from the inode currently being sent as long as the
1259+
* source extent is already processed, otherwise we could try
1260+
* to clone from an extent that does not exist yet at the
1261+
* destination of the stream.
1262+
*/
1263+
if (ino == bctx->cur_objectid &&
1264+
offset >= bctx->sctx->cur_inode_next_write_offset)
12571265
return 0;
12581266
}
12591267

0 commit comments

Comments
 (0)