Loading fs/btrfs/ctree.h +2 −0 Original line number Diff line number Diff line Loading @@ -4024,6 +4024,8 @@ void btrfs_get_block_group_info(struct list_head *groups_list, struct btrfs_ioctl_space_info *space); void update_ioctl_balance_args(struct btrfs_fs_info *fs_info, int lock, 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); /* file.c */ int btrfs_auto_defrag_init(void); Loading fs/btrfs/file.c +1 −0 Original line number Diff line number Diff line Loading @@ -2926,6 +2926,7 @@ const struct file_operations btrfs_file_operations = { #endif .copy_file_range = btrfs_copy_file_range, .clone_file_range = btrfs_clone_file_range, .dedupe_file_range = btrfs_dedupe_file_range, }; void btrfs_auto_defrag_exit(void) Loading fs/btrfs/ioctl.c +13 −97 Original line number Diff line number Diff line Loading @@ -2962,7 +2962,7 @@ static int btrfs_cmp_data(struct inode *src, u64 loff, struct inode *dst, flush_dcache_page(dst_page); if (memcmp(addr, dst_addr, cmp_len)) ret = BTRFS_SAME_DATA_DIFFERS; ret = -EBADE; kunmap_atomic(addr); kunmap_atomic(dst_addr); Loading Loading @@ -3098,53 +3098,16 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 olen, #define BTRFS_MAX_DEDUPE_LEN (16 * 1024 * 1024) static long btrfs_ioctl_file_extent_same(struct file *file, struct btrfs_ioctl_same_args __user *argp) ssize_t btrfs_dedupe_file_range(struct file *src_file, u64 loff, u64 olen, struct file *dst_file, u64 dst_loff) { struct btrfs_ioctl_same_args *same = NULL; struct btrfs_ioctl_same_extent_info *info; struct inode *src = file_inode(file); u64 off; u64 len; int i; int ret; unsigned long size; 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; bool is_admin = capable(CAP_SYS_ADMIN); u16 count; if (!(file->f_mode & FMODE_READ)) return -EINVAL; ssize_t res; ret = mnt_want_write_file(file); if (ret) return ret; if (get_user(count, &argp->dest_count)) { ret = -EFAULT; goto out; } size = offsetof(struct btrfs_ioctl_same_args __user, info[count]); same = memdup_user(argp, size); if (IS_ERR(same)) { ret = PTR_ERR(same); same = NULL; goto out; } off = same->logical_offset; len = same->length; /* * Limit the total length we will dedupe for each operation. * This is intended to bound the total time spent in this * ioctl to something sane. */ if (len > BTRFS_MAX_DEDUPE_LEN) len = BTRFS_MAX_DEDUPE_LEN; if (olen > BTRFS_MAX_DEDUPE_LEN) olen = BTRFS_MAX_DEDUPE_LEN; if (WARN_ON_ONCE(bs < PAGE_CACHE_SIZE)) { /* Loading @@ -3152,58 +3115,13 @@ static long btrfs_ioctl_file_extent_same(struct file *file, * result, btrfs_cmp_data() won't correctly handle * this situation without an update. */ ret = -EINVAL; goto out; } ret = -EISDIR; if (S_ISDIR(src->i_mode)) goto out; ret = -EACCES; if (!S_ISREG(src->i_mode)) goto out; /* pre-format output fields to sane values */ for (i = 0; i < count; i++) { same->info[i].bytes_deduped = 0ULL; same->info[i].status = 0; } for (i = 0, info = same->info; i < count; i++, info++) { struct inode *dst; struct fd dst_file = fdget(info->fd); if (!dst_file.file) { info->status = -EBADF; continue; } dst = file_inode(dst_file.file); if (!(is_admin || (dst_file.file->f_mode & FMODE_WRITE))) { info->status = -EINVAL; } else if (file->f_path.mnt != dst_file.file->f_path.mnt) { info->status = -EXDEV; } else if (S_ISDIR(dst->i_mode)) { info->status = -EISDIR; } else if (!S_ISREG(dst->i_mode)) { info->status = -EACCES; } else { info->status = btrfs_extent_same(src, off, len, dst, info->logical_offset); if (info->status == 0) info->bytes_deduped += len; } fdput(dst_file); return -EINVAL; } ret = copy_to_user(argp, same, size); if (ret) ret = -EFAULT; out: mnt_drop_write_file(file); kfree(same); return ret; res = btrfs_extent_same(src, loff, olen, dst, dst_loff); if (res) return res; return olen; } static int clone_finish_inode_update(struct btrfs_trans_handle *trans, Loading Loading @@ -5536,8 +5454,6 @@ long btrfs_ioctl(struct file *file, unsigned int return btrfs_ioctl_get_fslabel(file, argp); case BTRFS_IOC_SET_FSLABEL: return btrfs_ioctl_set_fslabel(file, argp); case BTRFS_IOC_FILE_EXTENT_SAME: return btrfs_ioctl_file_extent_same(file, argp); case BTRFS_IOC_GET_SUPPORTED_FEATURES: return btrfs_ioctl_get_supported_features(file, argp); case BTRFS_IOC_GET_FEATURES: Loading Loading
fs/btrfs/ctree.h +2 −0 Original line number Diff line number Diff line Loading @@ -4024,6 +4024,8 @@ void btrfs_get_block_group_info(struct list_head *groups_list, struct btrfs_ioctl_space_info *space); void update_ioctl_balance_args(struct btrfs_fs_info *fs_info, int lock, 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); /* file.c */ int btrfs_auto_defrag_init(void); Loading
fs/btrfs/file.c +1 −0 Original line number Diff line number Diff line Loading @@ -2926,6 +2926,7 @@ const struct file_operations btrfs_file_operations = { #endif .copy_file_range = btrfs_copy_file_range, .clone_file_range = btrfs_clone_file_range, .dedupe_file_range = btrfs_dedupe_file_range, }; void btrfs_auto_defrag_exit(void) Loading
fs/btrfs/ioctl.c +13 −97 Original line number Diff line number Diff line Loading @@ -2962,7 +2962,7 @@ static int btrfs_cmp_data(struct inode *src, u64 loff, struct inode *dst, flush_dcache_page(dst_page); if (memcmp(addr, dst_addr, cmp_len)) ret = BTRFS_SAME_DATA_DIFFERS; ret = -EBADE; kunmap_atomic(addr); kunmap_atomic(dst_addr); Loading Loading @@ -3098,53 +3098,16 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 olen, #define BTRFS_MAX_DEDUPE_LEN (16 * 1024 * 1024) static long btrfs_ioctl_file_extent_same(struct file *file, struct btrfs_ioctl_same_args __user *argp) ssize_t btrfs_dedupe_file_range(struct file *src_file, u64 loff, u64 olen, struct file *dst_file, u64 dst_loff) { struct btrfs_ioctl_same_args *same = NULL; struct btrfs_ioctl_same_extent_info *info; struct inode *src = file_inode(file); u64 off; u64 len; int i; int ret; unsigned long size; 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; bool is_admin = capable(CAP_SYS_ADMIN); u16 count; if (!(file->f_mode & FMODE_READ)) return -EINVAL; ssize_t res; ret = mnt_want_write_file(file); if (ret) return ret; if (get_user(count, &argp->dest_count)) { ret = -EFAULT; goto out; } size = offsetof(struct btrfs_ioctl_same_args __user, info[count]); same = memdup_user(argp, size); if (IS_ERR(same)) { ret = PTR_ERR(same); same = NULL; goto out; } off = same->logical_offset; len = same->length; /* * Limit the total length we will dedupe for each operation. * This is intended to bound the total time spent in this * ioctl to something sane. */ if (len > BTRFS_MAX_DEDUPE_LEN) len = BTRFS_MAX_DEDUPE_LEN; if (olen > BTRFS_MAX_DEDUPE_LEN) olen = BTRFS_MAX_DEDUPE_LEN; if (WARN_ON_ONCE(bs < PAGE_CACHE_SIZE)) { /* Loading @@ -3152,58 +3115,13 @@ static long btrfs_ioctl_file_extent_same(struct file *file, * result, btrfs_cmp_data() won't correctly handle * this situation without an update. */ ret = -EINVAL; goto out; } ret = -EISDIR; if (S_ISDIR(src->i_mode)) goto out; ret = -EACCES; if (!S_ISREG(src->i_mode)) goto out; /* pre-format output fields to sane values */ for (i = 0; i < count; i++) { same->info[i].bytes_deduped = 0ULL; same->info[i].status = 0; } for (i = 0, info = same->info; i < count; i++, info++) { struct inode *dst; struct fd dst_file = fdget(info->fd); if (!dst_file.file) { info->status = -EBADF; continue; } dst = file_inode(dst_file.file); if (!(is_admin || (dst_file.file->f_mode & FMODE_WRITE))) { info->status = -EINVAL; } else if (file->f_path.mnt != dst_file.file->f_path.mnt) { info->status = -EXDEV; } else if (S_ISDIR(dst->i_mode)) { info->status = -EISDIR; } else if (!S_ISREG(dst->i_mode)) { info->status = -EACCES; } else { info->status = btrfs_extent_same(src, off, len, dst, info->logical_offset); if (info->status == 0) info->bytes_deduped += len; } fdput(dst_file); return -EINVAL; } ret = copy_to_user(argp, same, size); if (ret) ret = -EFAULT; out: mnt_drop_write_file(file); kfree(same); return ret; res = btrfs_extent_same(src, loff, olen, dst, dst_loff); if (res) return res; return olen; } static int clone_finish_inode_update(struct btrfs_trans_handle *trans, Loading Loading @@ -5536,8 +5454,6 @@ long btrfs_ioctl(struct file *file, unsigned int return btrfs_ioctl_get_fslabel(file, argp); case BTRFS_IOC_SET_FSLABEL: return btrfs_ioctl_set_fslabel(file, argp); case BTRFS_IOC_FILE_EXTENT_SAME: return btrfs_ioctl_file_extent_same(file, argp); case BTRFS_IOC_GET_SUPPORTED_FEATURES: return btrfs_ioctl_get_supported_features(file, argp); case BTRFS_IOC_GET_FEATURES: Loading