bcachefs: Some reflink fixes
authorKent Overstreet <kent.overstreet@gmail.com>
Tue, 5 Nov 2019 03:22:13 +0000 (22:22 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:08:31 +0000 (17:08 -0400)
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
fs/bcachefs/reflink.c

index a1767ee8559109a6c3f5bf601efdf6576e15ae11..d17621b0713e37aaa87f3fe66480ad8443259269 100644 (file)
@@ -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);
index 6d45ae24479d8499ff0d0cc15df5deaee6607b19..6e71c5e8f9a20d078423ce615b169aca4419e8ef 100644 (file)
@@ -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;