Message ID | 20200404202022.30192-1-fdmanana@kernel.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Btrfs: fix lost i_size update after cloning inline extent | expand |
On Sat, Apr 4, 2020 at 9:21 PM <fdmanana@kernel.org> wrote: > > From: Filipe Manana <fdmanana@suse.com> > > When not using the NO_HOLES feature we were not marking the destination's > file range as written after cloning an inline extent into it. This can > lead to a data loss if the current destination file size is smaller than > the source file's size. > > Example: > > $ mkfs.btrfs -f -O ^no-holes /dev/sdc > $ mount /mnt/sdc /mnt > > $ echo "hello world" > /mnt/foo > $ cp --reflink=always /mnt/foo /mnt/bar > $ rm -f /mnt/foo > $ umount /mnt > > $ mount /mnt/sdc /mnt > $ cat /mnt/bar > $ > $ stat -c %s /mnt/bar > 0 > > # -> the file is empty, since we deleted foo, the data lost is forever > > Fix that by calling btrfs_inode_set_file_extent_range() after cloning an > inline extent. > > A test case for fstests will follow soon. > > Fixes: 9ddc959e802bf ("btrfs: use the file extent tree infrastructure") > Signed-off-by: Filipe Manana <fdmanana@suse.com> Reported-by: Johannes Hirte <johannes.hirte@datenkhaos.de> Link: https://lore.kernel.org/linux-btrfs/20200404193846.GA432065@latitude/ Tested-by: Johannes Hirte <johannes.hirte@datenkhaos.de> > --- > fs/btrfs/reflink.c | 1 + > 1 file changed, 1 insertion(+) > > diff --git a/fs/btrfs/reflink.c b/fs/btrfs/reflink.c > index d1973141d3bb..040009d1cc31 100644 > --- a/fs/btrfs/reflink.c > +++ b/fs/btrfs/reflink.c > @@ -264,6 +264,7 @@ static int clone_copy_inline_extent(struct inode *dst, > size); > inode_add_bytes(dst, datal); > set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &BTRFS_I(dst)->runtime_flags); > + ret = btrfs_inode_set_file_extent_range(BTRFS_I(dst), 0, aligned_end); > out: > if (!ret && !trans) { > /* > -- > 2.11.0 >
On Mon, Apr 06, 2020 at 11:51:20AM +0100, Filipe Manana wrote: > On Sat, Apr 4, 2020 at 9:21 PM <fdmanana@kernel.org> wrote: > > > > From: Filipe Manana <fdmanana@suse.com> > > > > When not using the NO_HOLES feature we were not marking the destination's > > file range as written after cloning an inline extent into it. This can > > lead to a data loss if the current destination file size is smaller than > > the source file's size. > > > > Example: > > > > $ mkfs.btrfs -f -O ^no-holes /dev/sdc > > $ mount /mnt/sdc /mnt > > > > $ echo "hello world" > /mnt/foo > > $ cp --reflink=always /mnt/foo /mnt/bar > > $ rm -f /mnt/foo > > $ umount /mnt > > > > $ mount /mnt/sdc /mnt > > $ cat /mnt/bar > > $ > > $ stat -c %s /mnt/bar > > 0 > > > > # -> the file is empty, since we deleted foo, the data lost is forever > > > > Fix that by calling btrfs_inode_set_file_extent_range() after cloning an > > inline extent. > > > > A test case for fstests will follow soon. > > > > Fixes: 9ddc959e802bf ("btrfs: use the file extent tree infrastructure") > > Signed-off-by: Filipe Manana <fdmanana@suse.com> > > Reported-by: Johannes Hirte <johannes.hirte@datenkhaos.de> > Link: https://lore.kernel.org/linux-btrfs/20200404193846.GA432065@latitude/ > Tested-by: Johannes Hirte <johannes.hirte@datenkhaos.de> Thanks, added to misc-next.
diff --git a/fs/btrfs/reflink.c b/fs/btrfs/reflink.c index d1973141d3bb..040009d1cc31 100644 --- a/fs/btrfs/reflink.c +++ b/fs/btrfs/reflink.c @@ -264,6 +264,7 @@ static int clone_copy_inline_extent(struct inode *dst, size); inode_add_bytes(dst, datal); set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &BTRFS_I(dst)->runtime_flags); + ret = btrfs_inode_set_file_extent_range(BTRFS_I(dst), 0, aligned_end); out: if (!ret && !trans) { /*