]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
Merge tag 'for-4.19-rc2-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 6 Sep 2018 16:04:45 +0000 (09:04 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 6 Sep 2018 16:04:45 +0000 (09:04 -0700)
Pull btrfs fixes from David Sterba:

 - fix for improper fsync after hardlink

 - fix for a corruption during file deduplication

 - use after free fixes

 - RCU warning fix

 - fix for buffered write to nodatacow file

* tag 'for-4.19-rc2-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  btrfs: Fix suspicious RCU usage warning in btrfs_debug_in_rcu
  btrfs: use after free in btrfs_quota_enable
  btrfs: btrfs_shrink_device should call commit transaction at the end
  btrfs: fix qgroup_free wrong num_bytes in btrfs_subvolume_reserve_metadata
  Btrfs: fix data corruption when deduplicating between different files
  Btrfs: sync log after logging new name
  Btrfs: fix unexpected failure of nocow buffered writes after snapshotting when low on space

1  2 
fs/btrfs/ctree.h
fs/btrfs/inode.c
fs/btrfs/ioctl.c

diff --combined fs/btrfs/ctree.h
index 53af9f5253f4fc5556e568b9b78397bba61e00cc,0b856da2fd3b35006b52dc77ddab4dfaadc3f22e..2cddfe7806a412e4ecf26a61887fe4474ab380de
@@@ -1280,6 -1280,7 +1280,7 @@@ struct btrfs_root 
        int send_in_progress;
        struct btrfs_subvolume_writers *subv_writers;
        atomic_t will_be_snapshotted;
+       atomic_t snapshot_force_cow;
  
        /* For qgroup metadata reserved space */
        spinlock_t qgroup_meta_rsv_lock;
@@@ -3217,9 -3218,8 +3218,9 @@@ void btrfs_get_block_group_info(struct 
                                struct btrfs_ioctl_space_info *space);
  void btrfs_update_ioctl_balance_args(struct btrfs_fs_info *fs_info,
                               struct btrfs_ioctl_balance_args *bargs);
 -ssize_t btrfs_dedupe_file_range(struct file *src_file, u64 loff, u64 olen,
 -                         struct file *dst_file, u64 dst_loff);
 +int btrfs_dedupe_file_range(struct file *src_file, loff_t src_loff,
 +                          struct file *dst_file, loff_t dst_loff,
 +                          u64 olen);
  
  /* file.c */
  int __init btrfs_auto_defrag_init(void);
@@@ -3390,9 -3390,9 +3391,9 @@@ do {                                                                    
  #define btrfs_debug(fs_info, fmt, args...) \
        btrfs_no_printk(fs_info, KERN_DEBUG fmt, ##args)
  #define btrfs_debug_in_rcu(fs_info, fmt, args...) \
-       btrfs_no_printk(fs_info, KERN_DEBUG fmt, ##args)
+       btrfs_no_printk_in_rcu(fs_info, KERN_DEBUG fmt, ##args)
  #define btrfs_debug_rl_in_rcu(fs_info, fmt, args...) \
-       btrfs_no_printk(fs_info, KERN_DEBUG fmt, ##args)
+       btrfs_no_printk_in_rcu(fs_info, KERN_DEBUG fmt, ##args)
  #define btrfs_debug_rl(fs_info, fmt, args...) \
        btrfs_no_printk(fs_info, KERN_DEBUG fmt, ##args)
  #endif
  do {                                                  \
        rcu_read_lock();                                \
        btrfs_printk(fs_info, fmt, ##args);             \
+       rcu_read_unlock();                              \
+ } while (0)
+ #define btrfs_no_printk_in_rcu(fs_info, fmt, args...) \
+ do {                                                  \
+       rcu_read_lock();                                \
+       btrfs_no_printk(fs_info, fmt, ##args);          \
        rcu_read_unlock();                              \
  } while (0)
  
diff --combined fs/btrfs/inode.c
index 9357a19d2bff2c76de1b29d2e221333b6f76da7e,cb09873ad270c3c493ff5e1bcec9a1110a6fd805..3ea5339603cff14f8dc103f6561091e83dc0b81a
@@@ -1271,7 -1271,7 +1271,7 @@@ static noinline int run_delalloc_nocow(
        u64 disk_num_bytes;
        u64 ram_bytes;
        int extent_type;
-       int ret, err;
+       int ret;
        int type;
        int nocow;
        int check_prev = 1;
@@@ -1403,11 -1403,8 +1403,8 @@@ next_slot
                         * if there are pending snapshots for this root,
                         * we fall into common COW way.
                         */
-                       if (!nolock) {
-                               err = btrfs_start_write_no_snapshotting(root);
-                               if (!err)
-                                       goto out_check;
-                       }
+                       if (!nolock && atomic_read(&root->snapshot_force_cow))
+                               goto out_check;
                        /*
                         * force cow if csum exists in the range.
                         * this ensure that csum for a given extent are
                        ret = csum_exist_in_range(fs_info, disk_bytenr,
                                                  num_bytes);
                        if (ret) {
-                               if (!nolock)
-                                       btrfs_end_write_no_snapshotting(root);
                                /*
                                 * ret could be -EIO if the above fails to read
                                 * metadata.
                                WARN_ON_ONCE(nolock);
                                goto out_check;
                        }
-                       if (!btrfs_inc_nocow_writers(fs_info, disk_bytenr)) {
-                               if (!nolock)
-                                       btrfs_end_write_no_snapshotting(root);
+                       if (!btrfs_inc_nocow_writers(fs_info, disk_bytenr))
                                goto out_check;
-                       }
                        nocow = 1;
                } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
                        extent_end = found_key.offset +
  out_check:
                if (extent_end <= start) {
                        path->slots[0]++;
-                       if (!nolock && nocow)
-                               btrfs_end_write_no_snapshotting(root);
                        if (nocow)
                                btrfs_dec_nocow_writers(fs_info, disk_bytenr);
                        goto next_slot;
                                             end, page_started, nr_written, 1,
                                             NULL);
                        if (ret) {
-                               if (!nolock && nocow)
-                                       btrfs_end_write_no_snapshotting(root);
                                if (nocow)
                                        btrfs_dec_nocow_writers(fs_info,
                                                                disk_bytenr);
                                          ram_bytes, BTRFS_COMPRESS_NONE,
                                          BTRFS_ORDERED_PREALLOC);
                        if (IS_ERR(em)) {
-                               if (!nolock && nocow)
-                                       btrfs_end_write_no_snapshotting(root);
                                if (nocow)
                                        btrfs_dec_nocow_writers(fs_info,
                                                                disk_bytenr);
                                             EXTENT_CLEAR_DATA_RESV,
                                             PAGE_UNLOCK | PAGE_SET_PRIVATE2);
  
-               if (!nolock && nocow)
-                       btrfs_end_write_no_snapshotting(root);
                cur_offset = extent_end;
  
                /*
@@@ -6295,10 -6278,8 +6278,10 @@@ static struct inode *btrfs_new_inode(st
        location->type = BTRFS_INODE_ITEM_KEY;
  
        ret = btrfs_insert_inode_locked(inode);
 -      if (ret < 0)
 +      if (ret < 0) {
 +              iput(inode);
                goto fail;
 +      }
  
        path->leave_spinning = 1;
        ret = btrfs_insert_empty_items(trans, root, path, key, sizes, nitems);
        return inode;
  
  fail_unlock:
 -      unlock_new_inode(inode);
 +      discard_new_inode(inode);
  fail:
        if (dir && name)
                BTRFS_I(dir)->index_cnt--;
        btrfs_free_path(path);
 -      iput(inode);
        return ERR_PTR(ret);
  }
  
@@@ -6465,6 -6447,7 +6448,6 @@@ static int btrfs_mknod(struct inode *di
        struct btrfs_root *root = BTRFS_I(dir)->root;
        struct inode *inode = NULL;
        int err;
 -      int drop_inode = 0;
        u64 objectid;
        u64 index = 0;
  
                        mode, &index);
        if (IS_ERR(inode)) {
                err = PTR_ERR(inode);
 +              inode = NULL;
                goto out_unlock;
        }
  
  
        err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
        if (err)
 -              goto out_unlock_inode;
 +              goto out_unlock;
  
        err = btrfs_add_nondir(trans, BTRFS_I(dir), dentry, BTRFS_I(inode),
                        0, index);
 -      if (err) {
 -              goto out_unlock_inode;
 -      } else {
 -              btrfs_update_inode(trans, root, inode);
 -              d_instantiate_new(dentry, inode);
 -      }
 +      if (err)
 +              goto out_unlock;
 +
 +      btrfs_update_inode(trans, root, inode);
 +      d_instantiate_new(dentry, inode);
  
  out_unlock:
        btrfs_end_transaction(trans);
        btrfs_btree_balance_dirty(fs_info);
 -      if (drop_inode) {
 +      if (err && inode) {
                inode_dec_link_count(inode);
 -              iput(inode);
 +              discard_new_inode(inode);
        }
        return err;
 -
 -out_unlock_inode:
 -      drop_inode = 1;
 -      unlock_new_inode(inode);
 -      goto out_unlock;
 -
  }
  
  static int btrfs_create(struct inode *dir, struct dentry *dentry,
        struct btrfs_trans_handle *trans;
        struct btrfs_root *root = BTRFS_I(dir)->root;
        struct inode *inode = NULL;
 -      int drop_inode_on_err = 0;
        int err;
        u64 objectid;
        u64 index = 0;
                        mode, &index);
        if (IS_ERR(inode)) {
                err = PTR_ERR(inode);
 +              inode = NULL;
                goto out_unlock;
        }
 -      drop_inode_on_err = 1;
        /*
        * If the active LSM wants to access the inode during
        * d_instantiate it needs these. Smack checks to see
  
        err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
        if (err)
 -              goto out_unlock_inode;
 +              goto out_unlock;
  
        err = btrfs_update_inode(trans, root, inode);
        if (err)
 -              goto out_unlock_inode;
 +              goto out_unlock;
  
        err = btrfs_add_nondir(trans, BTRFS_I(dir), dentry, BTRFS_I(inode),
                        0, index);
        if (err)
 -              goto out_unlock_inode;
 +              goto out_unlock;
  
        BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
        d_instantiate_new(dentry, inode);
  
  out_unlock:
        btrfs_end_transaction(trans);
 -      if (err && drop_inode_on_err) {
 +      if (err && inode) {
                inode_dec_link_count(inode);
 -              iput(inode);
 +              discard_new_inode(inode);
        }
        btrfs_btree_balance_dirty(fs_info);
        return err;
 -
 -out_unlock_inode:
 -      unlock_new_inode(inode);
 -      goto out_unlock;
 -
  }
  
  static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
                drop_inode = 1;
        } else {
                struct dentry *parent = dentry->d_parent;
+               int ret;
                err = btrfs_update_inode(trans, root, inode);
                if (err)
                        goto fail;
                                goto fail;
                }
                d_instantiate(dentry, inode);
-               btrfs_log_new_name(trans, BTRFS_I(inode), NULL, parent);
+               ret = btrfs_log_new_name(trans, BTRFS_I(inode), NULL, parent,
+                                        true, NULL);
+               if (ret == BTRFS_NEED_TRANS_COMMIT) {
+                       err = btrfs_commit_transaction(trans);
+                       trans = NULL;
+               }
        }
  
  fail:
@@@ -6695,7 -6697,6 +6685,7 @@@ static int btrfs_mkdir(struct inode *di
                        S_IFDIR | mode, &index);
        if (IS_ERR(inode)) {
                err = PTR_ERR(inode);
 +              inode = NULL;
                goto out_fail;
        }
  
  
        err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
        if (err)
 -              goto out_fail_inode;
 +              goto out_fail;
  
        btrfs_i_size_write(BTRFS_I(inode), 0);
        err = btrfs_update_inode(trans, root, inode);
        if (err)
 -              goto out_fail_inode;
 +              goto out_fail;
  
        err = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode),
                        dentry->d_name.name,
                        dentry->d_name.len, 0, index);
        if (err)
 -              goto out_fail_inode;
 +              goto out_fail;
  
        d_instantiate_new(dentry, inode);
        drop_on_err = 0;
  
  out_fail:
        btrfs_end_transaction(trans);
 -      if (drop_on_err) {
 +      if (err && inode) {
                inode_dec_link_count(inode);
 -              iput(inode);
 +              discard_new_inode(inode);
        }
        btrfs_btree_balance_dirty(fs_info);
        return err;
 -
 -out_fail_inode:
 -      unlock_new_inode(inode);
 -      goto out_fail;
  }
  
  static noinline int uncompress_inline(struct btrfs_path *path,
@@@ -9388,14 -9393,21 +9378,21 @@@ static int btrfs_rename_exchange(struc
        u64 new_idx = 0;
        u64 root_objectid;
        int ret;
-       int ret2;
        bool root_log_pinned = false;
        bool dest_log_pinned = false;
+       struct btrfs_log_ctx ctx_root;
+       struct btrfs_log_ctx ctx_dest;
+       bool sync_log_root = false;
+       bool sync_log_dest = false;
+       bool commit_transaction = false;
  
        /* we only allow rename subvolume link between subvolumes */
        if (old_ino != BTRFS_FIRST_FREE_OBJECTID && root != dest)
                return -EXDEV;
  
+       btrfs_init_log_ctx(&ctx_root, old_inode);
+       btrfs_init_log_ctx(&ctx_dest, new_inode);
        /* close the race window with snapshot create/destroy ioctl */
        if (old_ino == BTRFS_FIRST_FREE_OBJECTID)
                down_read(&fs_info->subvol_sem);
  
        if (root_log_pinned) {
                parent = new_dentry->d_parent;
-               btrfs_log_new_name(trans, BTRFS_I(old_inode), BTRFS_I(old_dir),
-                               parent);
+               ret = btrfs_log_new_name(trans, BTRFS_I(old_inode),
+                                        BTRFS_I(old_dir), parent,
+                                        false, &ctx_root);
+               if (ret == BTRFS_NEED_LOG_SYNC)
+                       sync_log_root = true;
+               else if (ret == BTRFS_NEED_TRANS_COMMIT)
+                       commit_transaction = true;
+               ret = 0;
                btrfs_end_log_trans(root);
                root_log_pinned = false;
        }
        if (dest_log_pinned) {
-               parent = old_dentry->d_parent;
-               btrfs_log_new_name(trans, BTRFS_I(new_inode), BTRFS_I(new_dir),
-                               parent);
+               if (!commit_transaction) {
+                       parent = old_dentry->d_parent;
+                       ret = btrfs_log_new_name(trans, BTRFS_I(new_inode),
+                                                BTRFS_I(new_dir), parent,
+                                                false, &ctx_dest);
+                       if (ret == BTRFS_NEED_LOG_SYNC)
+                               sync_log_dest = true;
+                       else if (ret == BTRFS_NEED_TRANS_COMMIT)
+                               commit_transaction = true;
+                       ret = 0;
+               }
                btrfs_end_log_trans(dest);
                dest_log_pinned = false;
        }
@@@ -9583,8 -9609,26 +9594,26 @@@ out_fail
                        dest_log_pinned = false;
                }
        }
-       ret2 = btrfs_end_transaction(trans);
-       ret = ret ? ret : ret2;
+       if (!ret && sync_log_root && !commit_transaction) {
+               ret = btrfs_sync_log(trans, BTRFS_I(old_inode)->root,
+                                    &ctx_root);
+               if (ret)
+                       commit_transaction = true;
+       }
+       if (!ret && sync_log_dest && !commit_transaction) {
+               ret = btrfs_sync_log(trans, BTRFS_I(new_inode)->root,
+                                    &ctx_dest);
+               if (ret)
+                       commit_transaction = true;
+       }
+       if (commit_transaction) {
+               ret = btrfs_commit_transaction(trans);
+       } else {
+               int ret2;
+               ret2 = btrfs_end_transaction(trans);
+               ret = ret ? ret : ret2;
+       }
  out_notrans:
        if (new_ino == BTRFS_FIRST_FREE_OBJECTID)
                up_read(&fs_info->subvol_sem);
@@@ -9661,6 -9705,9 +9690,9 @@@ static int btrfs_rename(struct inode *o
        int ret;
        u64 old_ino = btrfs_ino(BTRFS_I(old_inode));
        bool log_pinned = false;
+       struct btrfs_log_ctx ctx;
+       bool sync_log = false;
+       bool commit_transaction = false;
  
        if (btrfs_ino(BTRFS_I(new_dir)) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)
                return -EPERM;
        if (log_pinned) {
                struct dentry *parent = new_dentry->d_parent;
  
-               btrfs_log_new_name(trans, BTRFS_I(old_inode), BTRFS_I(old_dir),
-                               parent);
+               btrfs_init_log_ctx(&ctx, old_inode);
+               ret = btrfs_log_new_name(trans, BTRFS_I(old_inode),
+                                        BTRFS_I(old_dir), parent,
+                                        false, &ctx);
+               if (ret == BTRFS_NEED_LOG_SYNC)
+                       sync_log = true;
+               else if (ret == BTRFS_NEED_TRANS_COMMIT)
+                       commit_transaction = true;
+               ret = 0;
                btrfs_end_log_trans(root);
                log_pinned = false;
        }
@@@ -9856,7 -9910,19 +9895,19 @@@ out_fail
                btrfs_end_log_trans(root);
                log_pinned = false;
        }
-       btrfs_end_transaction(trans);
+       if (!ret && sync_log) {
+               ret = btrfs_sync_log(trans, BTRFS_I(old_inode)->root, &ctx);
+               if (ret)
+                       commit_transaction = true;
+       }
+       if (commit_transaction) {
+               ret = btrfs_commit_transaction(trans);
+       } else {
+               int ret2;
+               ret2 = btrfs_end_transaction(trans);
+               ret = ret ? ret : ret2;
+       }
  out_notrans:
        if (old_ino == BTRFS_FIRST_FREE_OBJECTID)
                up_read(&fs_info->subvol_sem);
@@@ -10056,6 -10122,7 +10107,6 @@@ static int btrfs_symlink(struct inode *
        struct btrfs_key key;
        struct inode *inode = NULL;
        int err;
 -      int drop_inode = 0;
        u64 objectid;
        u64 index = 0;
        int name_len;
                                objectid, S_IFLNK|S_IRWXUGO, &index);
        if (IS_ERR(inode)) {
                err = PTR_ERR(inode);
 +              inode = NULL;
                goto out_unlock;
        }
  
  
        err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
        if (err)
 -              goto out_unlock_inode;
 +              goto out_unlock;
  
        path = btrfs_alloc_path();
        if (!path) {
                err = -ENOMEM;
 -              goto out_unlock_inode;
 +              goto out_unlock;
        }
        key.objectid = btrfs_ino(BTRFS_I(inode));
        key.offset = 0;
                                      datasize);
        if (err) {
                btrfs_free_path(path);
 -              goto out_unlock_inode;
 +              goto out_unlock;
        }
        leaf = path->nodes[0];
        ei = btrfs_item_ptr(leaf, path->slots[0],
        if (!err)
                err = btrfs_add_nondir(trans, BTRFS_I(dir), dentry,
                                BTRFS_I(inode), 0, index);
 -      if (err) {
 -              drop_inode = 1;
 -              goto out_unlock_inode;
 -      }
 +      if (err)
 +              goto out_unlock;
  
        d_instantiate_new(dentry, inode);
  
  out_unlock:
        btrfs_end_transaction(trans);
 -      if (drop_inode) {
 +      if (err && inode) {
                inode_dec_link_count(inode);
 -              iput(inode);
 +              discard_new_inode(inode);
        }
        btrfs_btree_balance_dirty(fs_info);
        return err;
 -
 -out_unlock_inode:
 -      drop_inode = 1;
 -      unlock_new_inode(inode);
 -      goto out_unlock;
  }
  
  static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
@@@ -10373,14 -10446,14 +10424,14 @@@ static int btrfs_tmpfile(struct inode *
  
        ret = btrfs_init_inode_security(trans, inode, dir, NULL);
        if (ret)
 -              goto out_inode;
 +              goto out;
  
        ret = btrfs_update_inode(trans, root, inode);
        if (ret)
 -              goto out_inode;
 +              goto out;
        ret = btrfs_orphan_add(trans, BTRFS_I(inode));
        if (ret)
 -              goto out_inode;
 +              goto out;
  
        /*
         * We set number of links to 0 in btrfs_new_inode(), and here we set
         *    d_tmpfile() -> inode_dec_link_count() -> drop_nlink()
         */
        set_nlink(inode, 1);
 -      unlock_new_inode(inode);
        d_tmpfile(dentry, inode);
 +      unlock_new_inode(inode);
        mark_inode_dirty(inode);
 -
  out:
        btrfs_end_transaction(trans);
 -      if (ret)
 -              iput(inode);
 +      if (ret && inode)
 +              discard_new_inode(inode);
        btrfs_btree_balance_dirty(fs_info);
        return ret;
 -
 -out_inode:
 -      unlock_new_inode(inode);
 -      goto out;
 -
  }
  
  __attribute__((const))
diff --combined fs/btrfs/ioctl.c
index 63600dc2ac4cb104d0feb1df1d5b8ccc650d1091,011ddfcc96e2d5a483663c7fcf2206fd7580ed9b..d60b6caf09e857ef7c39e8ce337171d04cca1d72
@@@ -747,6 -747,7 +747,7 @@@ static int create_snapshot(struct btrfs
        struct btrfs_pending_snapshot *pending_snapshot;
        struct btrfs_trans_handle *trans;
        int ret;
+       bool snapshot_force_cow = false;
  
        if (!test_bit(BTRFS_ROOT_REF_COWS, &root->state))
                return -EINVAL;
                goto free_pending;
        }
  
+       /*
+        * Force new buffered writes to reserve space even when NOCOW is
+        * possible. This is to avoid later writeback (running dealloc) to
+        * fallback to COW mode and unexpectedly fail with ENOSPC.
+        */
        atomic_inc(&root->will_be_snapshotted);
        smp_mb__after_atomic();
        /* wait for no snapshot writes */
        if (ret)
                goto dec_and_free;
  
+       /*
+        * All previous writes have started writeback in NOCOW mode, so now
+        * we force future writes to fallback to COW mode during snapshot
+        * creation.
+        */
+       atomic_inc(&root->snapshot_force_cow);
+       snapshot_force_cow = true;
        btrfs_wait_ordered_extents(root, U64_MAX, 0, (u64)-1);
  
        btrfs_init_block_rsv(&pending_snapshot->block_rsv,
  fail:
        btrfs_subvolume_release_metadata(fs_info, &pending_snapshot->block_rsv);
  dec_and_free:
+       if (snapshot_force_cow)
+               atomic_dec(&root->snapshot_force_cow);
        if (atomic_dec_and_test(&root->will_be_snapshotted))
                wake_up_var(&root->will_be_snapshotted);
  free_pending:
@@@ -3453,6 -3469,25 +3469,25 @@@ static int btrfs_extent_same_range(stru
  
                same_lock_start = min_t(u64, loff, dst_loff);
                same_lock_len = max_t(u64, loff, dst_loff) + len - same_lock_start;
+       } else {
+               /*
+                * If the source and destination inodes are different, the
+                * source's range end offset matches the source's i_size, that
+                * i_size is not a multiple of the sector size, and the
+                * destination range does not go past the destination's i_size,
+                * we must round down the length to the nearest sector size
+                * multiple. If we don't do this adjustment we end replacing
+                * with zeroes the bytes in the range that starts at the
+                * deduplication range's end offset and ends at the next sector
+                * size multiple.
+                */
+               if (loff + olen == i_size_read(src) &&
+                   dst_loff + len < i_size_read(dst)) {
+                       const u64 sz = BTRFS_I(src)->root->fs_info->sectorsize;
+                       len = round_down(i_size_read(src), sz) - loff;
+                       olen = len;
+               }
        }
  
  again:
@@@ -3592,13 -3627,13 +3627,13 @@@ out_unlock
        return ret;
  }
  
 -ssize_t btrfs_dedupe_file_range(struct file *src_file, u64 loff, u64 olen,
 -                              struct file *dst_file, u64 dst_loff)
 +int btrfs_dedupe_file_range(struct file *src_file, loff_t src_loff,
 +                          struct file *dst_file, loff_t dst_loff,
 +                          u64 olen)
  {
        struct inode *src = file_inode(src_file);
        struct inode *dst = file_inode(dst_file);
        u64 bs = BTRFS_I(src)->root->fs_info->sb->s_blocksize;
 -      ssize_t res;
  
        if (WARN_ON_ONCE(bs < PAGE_SIZE)) {
                /*
                return -EINVAL;
        }
  
 -      res = btrfs_extent_same(src, loff, olen, dst, dst_loff);
 -      if (res)
 -              return res;
 -      return olen;
 +      return btrfs_extent_same(src, src_loff, olen, dst, dst_loff);
  }
  
  static int clone_finish_inode_update(struct btrfs_trans_handle *trans,