@@ -700,9 +700,15 @@ static int btrfs_remap_file_range_prep(struct file *file_in, loff_t pos_in,
{
struct inode *inode_in = file_inode(file_in);
struct inode *inode_out = file_inode(file_out);
- u64 bs = BTRFS_I(inode_out)->root->fs_info->sb->s_blocksize;
+ /*
+ * We don't support subpage write yet, thus for data writeback we
+ * must use PAGE_SIZE here. But for reflink we still support proper
+ * sector alignment.
+ */
+ u32 wb_bs = PAGE_SIZE;
bool same_inode = inode_out == inode_in;
- u64 wb_len;
+ u64 in_wb_len;
+ u64 out_wb_len;
int ret;
if (!(remap_flags & REMAP_FILE_DEDUP)) {
@@ -735,11 +741,21 @@ static int btrfs_remap_file_range_prep(struct file *file_in, loff_t pos_in,
* waits for the writeback to complete, i.e. for IO to be done, and
* not for the ordered extents to complete. We need to wait for them
* to complete so that new file extent items are in the fs tree.
+ *
+ * Also for subpage case, since at different offset the same length can
+ * cover different number of pages, we have to calculate the wb_len for
+ * each file.
*/
- if (*len == 0 && !(remap_flags & REMAP_FILE_DEDUP))
- wb_len = ALIGN(inode_in->i_size, bs) - ALIGN_DOWN(pos_in, bs);
- else
- wb_len = ALIGN(*len, bs);
+ if (*len == 0 && !(remap_flags & REMAP_FILE_DEDUP)) {
+ in_wb_len = round_up(inode_in->i_size, wb_bs) -
+ round_down(pos_in, wb_bs);
+ out_wb_len = in_wb_len;
+ } else {
+ in_wb_len = round_up(pos_in + *len, wb_bs) -
+ round_down(pos_in, wb_bs);
+ out_wb_len = round_up(pos_out + *len, wb_bs) -
+ round_down(pos_out, wb_bs);
+ }
/*
* Since we don't lock ranges, wait for ongoing lockless dio writes (as
@@ -771,12 +787,12 @@ static int btrfs_remap_file_range_prep(struct file *file_in, loff_t pos_in,
if (ret < 0)
return ret;
- ret = btrfs_wait_ordered_range(inode_in, ALIGN_DOWN(pos_in, bs),
- wb_len);
+ ret = btrfs_wait_ordered_range(inode_in, round_down(pos_in, wb_bs),
+ in_wb_len);
if (ret < 0)
return ret;
- ret = btrfs_wait_ordered_range(inode_out, ALIGN_DOWN(pos_out, bs),
- wb_len);
+ ret = btrfs_wait_ordered_range(inode_out, round_down(pos_out, wb_bs),
+ out_wb_len);
if (ret < 0)
return ret;
Since we don't support subpage writeback yet, let btrfs_remap_file_range_prep() to do full page writeback. This only affects subpage support, as the regular sectorsize support already has its sectorsize == PAGE_SIZE. Signed-off-by: Qu Wenruo <wqu@suse.com> --- fs/btrfs/reflink.c | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-)