From 677fc0562a237f6cfc1551e37673707096905ca7 Mon Sep 17 00:00:00 2001
From: Kent Overstreet <kent.overstreet@gmail.com>
Date: Mon, 4 Nov 2019 22:22:13 -0500
Subject: [PATCH] bcachefs: Some reflink fixes

len might fit into a loff_t when aligned_len does not - make sure we use
a u64 for aligned_len. Also, we weren't always extending the inode
correctly.

Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
---
 fs/bcachefs/fs-io.c   | 13 ++++++-------
 fs/bcachefs/reflink.c |  4 +++-
 2 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/fs/bcachefs/fs-io.c b/fs/bcachefs/fs-io.c
index a1767ee855910..d17621b0713e3 100644
--- a/fs/bcachefs/fs-io.c
+++ b/fs/bcachefs/fs-io.c
@@ -2799,8 +2799,8 @@ loff_t bch2_remap_file_range(struct file *file_src, loff_t pos_src,
 	struct bch_inode_info *dst = file_bch_inode(file_dst);
 	struct bch_fs *c = src->v.i_sb->s_fs_info;
 	s64 i_sectors_delta = 0;
+	u64 aligned_len;
 	loff_t ret = 0;
-	loff_t aligned_len;
 
 	if (remap_flags & ~(REMAP_FILE_DEDUP|REMAP_FILE_ADVISORY))
 		return -EINVAL;
@@ -2829,10 +2829,10 @@ loff_t bch2_remap_file_range(struct file *file_src, loff_t pos_src,
 	if (ret < 0 || len == 0)
 		goto err;
 
-	aligned_len = round_up(len, block_bytes(c));
+	aligned_len = round_up((u64) len, block_bytes(c));
 
 	ret = write_invalidate_inode_pages_range(dst->v.i_mapping,
-				pos_dst, pos_dst + aligned_len);
+				pos_dst, pos_dst + len - 1);
 	if (ret)
 		goto err;
 
@@ -2847,18 +2847,17 @@ loff_t bch2_remap_file_range(struct file *file_src, loff_t pos_src,
 	if (ret < 0)
 		goto err;
 
-	ret <<= 9;
 	/*
 	 * due to alignment, we might have remapped slightly more than requsted
 	 */
-	ret = min(ret, len);
+	ret = min((u64) ret << 9, (u64) len);
 
 	/* XXX get a quota reservation */
 	i_sectors_acct(c, dst, NULL, i_sectors_delta);
 
 	spin_lock(&dst->v.i_lock);
-	if (pos_dst + len > dst->v.i_size)
-		i_size_write(&dst->v, pos_dst + len);
+	if (pos_dst + ret > dst->v.i_size)
+		i_size_write(&dst->v, pos_dst + ret);
 	spin_unlock(&dst->v.i_lock);
 err:
 	bch2_unlock_inodes(INODE_LOCK|INODE_PAGECACHE_BLOCK, src, dst);
diff --git a/fs/bcachefs/reflink.c b/fs/bcachefs/reflink.c
index 6d45ae24479d8..6e71c5e8f9a20 100644
--- a/fs/bcachefs/reflink.c
+++ b/fs/bcachefs/reflink.c
@@ -290,10 +290,12 @@ err:
 		ret2 = PTR_ERR_OR_ZERO(inode_iter);
 
 		if (!ret2 &&
-		    inode_u.bi_size < new_i_size)
+		    inode_u.bi_size < new_i_size) {
+			inode_u.bi_size = new_i_size;
 			ret2  = bch2_inode_write(&trans, inode_iter, &inode_u) ?:
 				bch2_trans_commit(&trans, NULL, journal_seq,
 						  BTREE_INSERT_ATOMIC);
+		}
 	} while (ret2 == -EINTR);
 
 	ret = bch2_trans_exit(&trans) ?: ret;
-- 
2.30.2