android_kernel_xiaomi_sm8450/fs/btrfs
Filipe Manana 688a45aff2 btrfs: send: avoid unaligned encoded writes when attempting to clone range
[ Upstream commit a11452a3709e217492798cf3686ac2cc8eb3fb51 ]

When trying to see if we can clone a file range, there are cases where we
end up sending two write operations in case the inode from the source root
has an i_size that is not sector size aligned and the length from the
current offset to its i_size is less than the remaining length we are
trying to clone.

Issuing two write operations when we could instead issue a single write
operation is not incorrect. However it is not optimal, specially if the
extents are compressed and the flag BTRFS_SEND_FLAG_COMPRESSED was passed
to the send ioctl. In that case we can end up sending an encoded write
with an offset that is not sector size aligned, which makes the receiver
fallback to decompressing the data and writing it using regular buffered
IO (so re-compressing the data in case the fs is mounted with compression
enabled), because encoded writes fail with -EINVAL when an offset is not
sector size aligned.

The following example, which triggered a bug in the receiver code for the
fallback logic of decompressing + regular buffer IO and is fixed by the
patchset referred in a Link at the bottom of this changelog, is an example
where we have the non-optimal behaviour due to an unaligned encoded write:

   $ cat test.sh
   #!/bin/bash

   DEV=/dev/sdj
   MNT=/mnt/sdj

   mkfs.btrfs -f $DEV > /dev/null
   mount -o compress $DEV $MNT

   # File foo has a size of 33K, not aligned to the sector size.
   xfs_io -f -c "pwrite -S 0xab 0 33K" $MNT/foo

   xfs_io -f -c "pwrite -S 0xcd 0 64K" $MNT/bar

   # Now clone the first 32K of file bar into foo at offset 0.
   xfs_io -c "reflink $MNT/bar 0 0 32K" $MNT/foo

   # Snapshot the default subvolume and create a full send stream (v2).
   btrfs subvolume snapshot -r $MNT $MNT/snap

   btrfs send --compressed-data -f /tmp/test.send $MNT/snap

   echo -e "\nFile bar in the original filesystem:"
   od -A d -t x1 $MNT/snap/bar

   umount $MNT
   mkfs.btrfs -f $DEV > /dev/null
   mount $DEV $MNT

   echo -e "\nReceiving stream in a new filesystem..."
   btrfs receive -f /tmp/test.send $MNT

   echo -e "\nFile bar in the new filesystem:"
   od -A d -t x1 $MNT/snap/bar

   umount $MNT

Before this patch, the send stream included one regular write and one
encoded write for file 'bar', with the later being not sector size aligned
and causing the receiver to fallback to decompression + buffered writes.
The output of the btrfs receive command in verbose mode (-vvv):

   (...)
   mkfile o258-7-0
   rename o258-7-0 -> bar
   utimes
   clone bar - source=foo source offset=0 offset=0 length=32768
   write bar - offset=32768 length=1024
   encoded_write bar - offset=33792, len=4096, unencoded_offset=33792, unencoded_file_len=31744, unencoded_len=65536, compression=1, encryption=0
   encoded_write bar - falling back to decompress and write due to errno 22 ("Invalid argument")
   (...)

This patch avoids the regular write followed by an unaligned encoded write
so that we end up sending a single encoded write that is aligned. So after
this patch the stream content is (output of btrfs receive -vvv):

   (...)
   mkfile o258-7-0
   rename o258-7-0 -> bar
   utimes
   clone bar - source=foo source offset=0 offset=0 length=32768
   encoded_write bar - offset=32768, len=4096, unencoded_offset=32768, unencoded_file_len=32768, unencoded_len=65536, compression=1, encryption=0
   (...)

So we get more optimal behaviour and avoid the silent data loss bug in
versions of btrfs-progs affected by the bug referred by the Link tag
below (btrfs-progs v5.19, v5.19.1, v6.0 and v6.0.1).

Link: https://lore.kernel.org/linux-btrfs/cover.1668529099.git.fdmanana@suse.com/
Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
2022-12-14 11:31:53 +01:00
..
tests btrfs: remove pointless and double ulist frees in error paths of qgroup tests 2022-11-25 17:45:40 +01:00
acl.c btrfs: cleanup btrfs_setxattr_trans and drop transaction parameter 2019-04-29 19:02:44 +02:00
async-thread.c btrfs: fix memory ordering between normal and ordered work functions 2021-11-26 10:39:20 +01:00
async-thread.h Btrfs: fix crash during unmount due to race with delayed inode workers 2020-03-23 17:01:51 +01:00
backref.c btrfs: sink iterator parameter to btrfs_ioctl_logical_to_ino 2022-12-08 11:23:53 +01:00
backref.h btrfs: sink iterator parameter to btrfs_ioctl_logical_to_ino 2022-12-08 11:23:53 +01:00
block-group.c btrfs: reset block group chunk force if we have to wait 2022-08-21 15:16:20 +02:00
block-group.h btrfs: fix race between writes to swap files and scrub 2021-03-09 11:11:11 +01:00
block-rsv.c btrfs: print the block rsv type when we fail our reservation 2020-11-05 13:02:05 +01:00
block-rsv.h btrfs: Remove __ prefix from btrfs_block_rsv_release 2020-03-23 17:01:55 +01:00
btrfs_inode.h btrfs: fix race between marking inode needs to be logged and log syncing 2021-09-03 10:09:28 +02:00
check-integrity.c btrfs: check-integrity: remove unnecessary failure messages during memory allocation 2020-07-27 12:55:21 +02:00
check-integrity.h btrfs: remove btrfsic_submit_bh() 2020-03-23 17:01:39 +01:00
compression.c btrfs: mark compressed range uptodate only if all bio succeed 2021-08-04 12:46:39 +02:00
compression.h btrfs: compression: move declarations to header 2020-10-07 12:06:55 +02:00
ctree.c btrfs: check the root node for uptodate before returning it 2022-01-27 10:54:27 +01:00
ctree.h btrfs: fix race between writes to swap files and scrub 2021-03-09 11:11:11 +01:00
delalloc-space.c btrfs: add btrfs_reserve_data_bytes and use it 2020-10-07 12:06:52 +02:00
delalloc-space.h btrfs: make btrfs_delalloc_reserve_space take btrfs_inode 2020-07-27 12:55:36 +02:00
delayed-inode.c btrfs: abort transaction if we fail to update the delayed inode 2021-07-14 16:55:55 +02:00
delayed-inode.h btrfs: delayed-inode: Replace zero-length array with flexible-array member 2020-03-23 17:01:53 +01:00
delayed-ref.c btrfs: account for new extents being deleted in total_bytes_pinned 2021-03-04 11:38:30 +01:00
delayed-ref.h btrfs: handle space_info::total_bytes_pinned inside the delayed ref itself 2021-03-04 11:38:30 +01:00
dev-replace.c btrfs: add info when mount fails due to stale replace target 2022-08-31 17:15:22 +02:00
dev-replace.h btrfs: add __pure attribute to functions 2019-11-18 12:46:52 +01:00
dir-item.c btrfs: remove unused parameter fs_info from btrfs_extend_item 2019-04-29 19:02:50 +02:00
discard.c btrfs: merge critical sections of discard lock in workfn 2021-01-19 18:27:24 +01:00
discard.h btrfs: discard: Use the correct style for SPDX License Identifier 2020-04-20 17:43:42 +02:00
disk-io.c btrfs: fix hang during unmount when stopping a space reclaim worker 2022-10-05 10:38:37 +02:00
disk-io.h btrfs: add a helper to read the tree_root commit root for backref lookup 2020-10-26 15:04:57 +01:00
export.c btrfs: fix type of parameter generation in btrfs_get_dentry 2022-11-10 18:14:25 +01:00
export.h btrfs: fix type of parameter generation in btrfs_get_dentry 2022-11-10 18:14:25 +01:00
extent_io.c btrfs: clear extent buffer uptodate when we fail to write it 2021-12-14 11:32:38 +01:00
extent_io.h btrfs: fix qgroup reserve overflow the qgroup limit 2022-04-13 21:01:08 +02:00
extent_map.c Btrfs: fix race between using extent maps and merging them 2020-02-12 17:16:46 +01:00
extent_map.h btrfs: remove extent_map::bdev 2019-11-18 23:43:44 +01:00
extent-io-tree.h btrfs: remove struct extent_io_ops 2020-10-07 12:13:25 +02:00
extent-tree.c btrfs: unlock newly allocated extent buffer after error 2021-10-20 11:44:59 +02:00
file-item.c btrfs: replace BUG_ON() in btrfs_csum_one_bio() with proper error handling 2021-10-09 14:40:56 +02:00
file.c btrfs: fix fallocate to use file_modified to update permissions consistently 2022-04-20 09:23:19 +02:00
free-space-cache.c btrfs: fix race between extent freeing/allocation when using bitmaps 2021-03-09 11:11:11 +01:00
free-space-cache.h btrfs: let btrfs_return_cluster_to_free_space() return void 2020-07-27 12:55:21 +02:00
free-space-tree.c btrfs: fix possible free space tree corruption with online conversion 2021-02-03 23:28:40 +01:00
free-space-tree.h btrfs: rename btrfs_block_group_cache 2019-11-18 17:51:51 +01:00
inode-item.c btrfs: Make btrfs_find_name_in_ext_backref return struct btrfs_inode_extref 2019-09-09 14:59:16 +02:00
inode-map.c btrfs: make btrfs_delalloc_reserve_space take btrfs_inode 2020-07-27 12:55:36 +02:00
inode-map.h btrfs: replace GPL boilerplate by SPDX -- headers 2018-04-12 16:29:46 +02:00
inode.c btrfs: return -EAGAIN for NOWAIT dio reads/writes on compressed and inline extents 2022-07-21 21:20:01 +02:00
ioctl.c btrfs: free btrfs_path before copying inodes to userspace 2022-12-08 11:23:53 +01:00
Kconfig btrfs: disable build on platforms having page size 256K 2021-07-14 16:55:56 +02:00
locking.c btrfs: add nesting tags to the locking helpers 2020-10-07 12:12:16 +02:00
locking.h btrfs: introduce BTRFS_NESTING_NEW_ROOT for adding new roots 2020-10-07 12:12:17 +02:00
lzo.c btrfs: compression: inline free_workspace 2019-11-18 12:46:59 +01:00
Makefile Btrfs: move all reflink implementation code into its own file 2020-03-23 17:01:54 +01:00
misc.h btrfs: rename tree_entry to rb_simple_node and export it 2020-05-25 11:25:19 +02:00
ordered-data.c btrfs: remove inode argument from btrfs_start_ordered_extent 2020-10-07 12:13:22 +02:00
ordered-data.h btrfs: remove inode argument from btrfs_start_ordered_extent 2020-10-07 12:13:22 +02:00
orphan.c btrfs: replace GPL boilerplate by SPDX -- sources 2018-04-12 16:29:51 +02:00
print-tree.c btrfs: print the actual offset in btrfs_root_name 2021-01-27 11:55:06 +01:00
print-tree.h btrfs: print the actual offset in btrfs_root_name 2021-01-27 11:55:06 +01:00
props.c btrfs: simplify iget helpers 2020-05-25 11:25:37 +02:00
props.h btrfs: delete unused function btrfs_set_prop_trans 2019-04-29 19:02:54 +02:00
qgroup.c btrfs: qgroup: fix sleep from invalid context bug in btrfs_qgroup_inherit() 2022-12-08 11:23:54 +01:00
qgroup.h btrfs: export and rename qgroup_reserve_meta 2021-03-11 14:17:22 +01:00
raid56.c btrfs: raid56: don't trust any cached sector in __raid56_parity_recover() 2022-08-21 15:16:27 +02:00
raid56.h btrfs: constify map parameter for nr_parity_stripes and nr_data_stripes 2019-07-01 13:34:58 +02:00
rcu-string.h btrfs: rcu-string: Replace zero-length array with flexible-array member 2020-03-23 17:01:53 +01:00
reada.c btrfs: fix readahead hang and use-after-free after removing a device 2020-10-26 15:03:59 +01:00
ref-verify.c btrfs: ref-verify: fix memory leak in btrfs_ref_tree_mod 2020-11-05 13:03:39 +01:00
ref-verify.h btrfs: ref-verify: Use btrfs_ref to refactor btrfs_ref_tree_mod() 2019-04-29 19:02:49 +02:00
reflink.c btrfs: fix unexpected error path when reflinking an inline extent 2022-04-08 14:40:04 +02:00
reflink.h Btrfs: move all reflink implementation code into its own file 2020-03-23 17:01:54 +01:00
relocation.c btrfs: convert logic BUG_ON()'s in replace_path to ASSERT()'s 2021-05-11 14:47:22 +02:00
root-tree.c btrfs: fix silent failure when deleting root reference 2022-08-31 17:15:21 +02:00
scrub.c btrfs: scrub: try to fix super block errors 2022-10-26 13:25:51 +02:00
send.c btrfs: send: avoid unaligned encoded writes when attempting to clone range 2022-12-14 11:31:53 +01:00
send.h btrfs: send: avoid copying file data 2020-10-07 12:13:17 +02:00
space-info.c btrfs: prevent __btrfs_dump_space_info() to underflow its free space 2021-09-30 10:11:00 +02:00
space-info.h btrfs: handle space_info::total_bytes_pinned inside the delayed ref itself 2021-03-04 11:38:30 +01:00
struct-funcs.c btrfs: use unaligned helpers for stack and header set/get helpers 2020-10-07 12:13:23 +02:00
super.c btrfs: add error messages to all unrecognized mount options 2022-06-29 08:59:45 +02:00
sysfs.c btrfs: sysfs: normalize the error handling branch in btrfs_init_sysfs() 2022-12-02 17:40:06 +01:00
sysfs.h btrfs: split and refactor btrfs_sysfs_remove_devices_dir 2020-10-07 12:12:21 +02:00
transaction.c btrfs: clear defrag status of a root if starting transaction fails 2021-07-14 16:55:40 +02:00
transaction.h btrfs: fix race between marking inode needs to be logged and log syncing 2021-09-03 10:09:28 +02:00
tree-checker.c btrfs: tree-checker: check item_size for dev_item 2022-03-02 11:42:45 +01:00
tree-checker.h btrfs: get fs_info from eb in btrfs_check_chunk_valid 2019-04-29 19:02:39 +02:00
tree-defrag.c btrfs: remove unused btrfs_root::defrag_trans_start 2020-07-27 12:55:28 +02:00
tree-log.c btrfs: fix lost error handling when looking up extended ref on log replay 2022-08-25 11:37:51 +02:00
tree-log.h btrfs: make fast fsyncs wait only for writeback 2020-10-07 12:06:56 +02:00
ulist.c btrfs: replace GPL boilerplate by SPDX -- sources 2018-04-12 16:29:51 +02:00
ulist.h btrfs: replace GPL boilerplate by SPDX -- headers 2018-04-12 16:29:46 +02:00
uuid-tree.c btrfs: simplify root lookup by id 2020-05-25 11:25:36 +02:00
volumes.c btrfs: harden identification of a stale device 2022-09-08 11:11:40 +02:00
volumes.h btrfs: fix lockdep warning due to seqcount_mutex on 32bit arch 2021-02-03 23:28:40 +01:00
xattr.c btrfs: check if root is readonly while setting security xattr 2022-08-31 17:15:22 +02:00
xattr.h btrfs: cleanup btrfs_setxattr_trans and drop transaction parameter 2019-04-29 19:02:44 +02:00
zlib.c btrfs: use larger zlib buffer for s390 hardware compression 2020-01-31 10:30:40 -08:00
zstd.c btrfs: compression: inline free_workspace 2019-11-18 12:46:59 +01:00