Message ID | 20191030122311.31349-1-fdmanana@kernel.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Btrfs: send, allow clone operations within the same file | expand |
On Wed, Oct 30, 2019 at 12:23:11PM +0000, fdmanana@kernel.org wrote: > From: Filipe Manana <fdmanana@suse.com> > > 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 > a96fbc72884fcb ("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 > > Signed-off-by: Filipe Manana <fdmanana@suse.com> Reviewed-by: Josef Bacik <josef@toxicpanda.com> Thanks, Josef
On Wed, Oct 30, 2019 at 12:23:11PM +0000, fdmanana@kernel.org wrote: > From: Filipe Manana <fdmanana@suse.com> > > 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 > a96fbc72884fcb ("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 > > Signed-off-by: Filipe Manana <fdmanana@suse.com> Added to misc-next, thanks.
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 518ec1265a0c..1624df5e6aa6 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -1256,12 +1256,20 @@ static int __iterate_backrefs(u64 ino, u64 offset, u64 root, void *ctx_) */ if (found->root == bctx->sctx->send_root) { /* - * TODO for the moment we don't accept clones from the inode - * that is currently send. We may change this when - * BTRFS_IOC_CLONE_RANGE supports cloning from and to the same - * file. + * If the source inode was not yet processed we can't issue a + * clone operation, as the source extent does not exist yet at + * the destination of the stream. */ - if (ino >= bctx->cur_objectid) + if (ino > bctx->cur_objectid) + return 0; + /* + * We clone from the inode currently being sent as long as the + * source extent is already processed, otherwise we could try + * to clone from an extent that does not exist yet at the + * destination of the stream. + */ + if (ino == bctx->cur_objectid && + offset >= bctx->sctx->cur_inode_next_write_offset) return 0; }