aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/ctree.h2
-rw-r--r--fs/btrfs/file.c1
-rw-r--r--fs/btrfs/ioctl.c110
3 files changed, 16 insertions, 97 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index dd4733fa882c..b7e4e344e8e0 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -4024,6 +4024,8 @@ void btrfs_get_block_group_info(struct list_head *groups_list,
4024 struct btrfs_ioctl_space_info *space); 4024 struct btrfs_ioctl_space_info *space);
4025void update_ioctl_balance_args(struct btrfs_fs_info *fs_info, int lock, 4025void update_ioctl_balance_args(struct btrfs_fs_info *fs_info, int lock,
4026 struct btrfs_ioctl_balance_args *bargs); 4026 struct btrfs_ioctl_balance_args *bargs);
4027ssize_t btrfs_dedupe_file_range(struct file *src_file, u64 loff, u64 olen,
4028 struct file *dst_file, u64 dst_loff);
4027 4029
4028/* file.c */ 4030/* file.c */
4029int btrfs_auto_defrag_init(void); 4031int btrfs_auto_defrag_init(void);
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 232e300a6c93..d012e0a96ec3 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -2926,6 +2926,7 @@ const struct file_operations btrfs_file_operations = {
2926#endif 2926#endif
2927 .copy_file_range = btrfs_copy_file_range, 2927 .copy_file_range = btrfs_copy_file_range,
2928 .clone_file_range = btrfs_clone_file_range, 2928 .clone_file_range = btrfs_clone_file_range,
2929 .dedupe_file_range = btrfs_dedupe_file_range,
2929}; 2930};
2930 2931
2931void btrfs_auto_defrag_exit(void) 2932void btrfs_auto_defrag_exit(void)
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 85b1caeeec85..e21997385d14 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2962,7 +2962,7 @@ static int btrfs_cmp_data(struct inode *src, u64 loff, struct inode *dst,
2962 flush_dcache_page(dst_page); 2962 flush_dcache_page(dst_page);
2963 2963
2964 if (memcmp(addr, dst_addr, cmp_len)) 2964 if (memcmp(addr, dst_addr, cmp_len))
2965 ret = BTRFS_SAME_DATA_DIFFERS; 2965 ret = -EBADE;
2966 2966
2967 kunmap_atomic(addr); 2967 kunmap_atomic(addr);
2968 kunmap_atomic(dst_addr); 2968 kunmap_atomic(dst_addr);
@@ -3098,53 +3098,16 @@ out_unlock:
3098 3098
3099#define BTRFS_MAX_DEDUPE_LEN (16 * 1024 * 1024) 3099#define BTRFS_MAX_DEDUPE_LEN (16 * 1024 * 1024)
3100 3100
3101static long btrfs_ioctl_file_extent_same(struct file *file, 3101ssize_t btrfs_dedupe_file_range(struct file *src_file, u64 loff, u64 olen,
3102 struct btrfs_ioctl_same_args __user *argp) 3102 struct file *dst_file, u64 dst_loff)
3103{ 3103{
3104 struct btrfs_ioctl_same_args *same = NULL; 3104 struct inode *src = file_inode(src_file);
3105 struct btrfs_ioctl_same_extent_info *info; 3105 struct inode *dst = file_inode(dst_file);
3106 struct inode *src = file_inode(file);
3107 u64 off;
3108 u64 len;
3109 int i;
3110 int ret;
3111 unsigned long size;
3112 u64 bs = BTRFS_I(src)->root->fs_info->sb->s_blocksize; 3106 u64 bs = BTRFS_I(src)->root->fs_info->sb->s_blocksize;
3113 bool is_admin = capable(CAP_SYS_ADMIN); 3107 ssize_t res;
3114 u16 count;
3115
3116 if (!(file->f_mode & FMODE_READ))
3117 return -EINVAL;
3118 3108
3119 ret = mnt_want_write_file(file); 3109 if (olen > BTRFS_MAX_DEDUPE_LEN)
3120 if (ret) 3110 olen = BTRFS_MAX_DEDUPE_LEN;
3121 return ret;
3122
3123 if (get_user(count, &argp->dest_count)) {
3124 ret = -EFAULT;
3125 goto out;
3126 }
3127
3128 size = offsetof(struct btrfs_ioctl_same_args __user, info[count]);
3129
3130 same = memdup_user(argp, size);
3131
3132 if (IS_ERR(same)) {
3133 ret = PTR_ERR(same);
3134 same = NULL;
3135 goto out;
3136 }
3137
3138 off = same->logical_offset;
3139 len = same->length;
3140
3141 /*
3142 * Limit the total length we will dedupe for each operation.
3143 * This is intended to bound the total time spent in this
3144 * ioctl to something sane.
3145 */
3146 if (len > BTRFS_MAX_DEDUPE_LEN)
3147 len = BTRFS_MAX_DEDUPE_LEN;
3148 3111
3149 if (WARN_ON_ONCE(bs < PAGE_CACHE_SIZE)) { 3112 if (WARN_ON_ONCE(bs < PAGE_CACHE_SIZE)) {
3150 /* 3113 /*
@@ -3152,58 +3115,13 @@ static long btrfs_ioctl_file_extent_same(struct file *file,
3152 * result, btrfs_cmp_data() won't correctly handle 3115 * result, btrfs_cmp_data() won't correctly handle
3153 * this situation without an update. 3116 * this situation without an update.
3154 */ 3117 */
3155 ret = -EINVAL; 3118 return -EINVAL;
3156 goto out;
3157 }
3158
3159 ret = -EISDIR;
3160 if (S_ISDIR(src->i_mode))
3161 goto out;
3162
3163 ret = -EACCES;
3164 if (!S_ISREG(src->i_mode))
3165 goto out;
3166
3167 /* pre-format output fields to sane values */
3168 for (i = 0; i < count; i++) {
3169 same->info[i].bytes_deduped = 0ULL;
3170 same->info[i].status = 0;
3171 }
3172
3173 for (i = 0, info = same->info; i < count; i++, info++) {
3174 struct inode *dst;
3175 struct fd dst_file = fdget(info->fd);
3176 if (!dst_file.file) {
3177 info->status = -EBADF;
3178 continue;
3179 }
3180 dst = file_inode(dst_file.file);
3181
3182 if (!(is_admin || (dst_file.file->f_mode & FMODE_WRITE))) {
3183 info->status = -EINVAL;
3184 } else if (file->f_path.mnt != dst_file.file->f_path.mnt) {
3185 info->status = -EXDEV;
3186 } else if (S_ISDIR(dst->i_mode)) {
3187 info->status = -EISDIR;
3188 } else if (!S_ISREG(dst->i_mode)) {
3189 info->status = -EACCES;
3190 } else {
3191 info->status = btrfs_extent_same(src, off, len, dst,
3192 info->logical_offset);
3193 if (info->status == 0)
3194 info->bytes_deduped += len;
3195 }
3196 fdput(dst_file);
3197 } 3119 }
3198 3120
3199 ret = copy_to_user(argp, same, size); 3121 res = btrfs_extent_same(src, loff, olen, dst, dst_loff);
3200 if (ret) 3122 if (res)
3201 ret = -EFAULT; 3123 return res;
3202 3124 return olen;
3203out:
3204 mnt_drop_write_file(file);
3205 kfree(same);
3206 return ret;
3207} 3125}
3208 3126
3209static int clone_finish_inode_update(struct btrfs_trans_handle *trans, 3127static int clone_finish_inode_update(struct btrfs_trans_handle *trans,
@@ -5536,8 +5454,6 @@ long btrfs_ioctl(struct file *file, unsigned int
5536 return btrfs_ioctl_get_fslabel(file, argp); 5454 return btrfs_ioctl_get_fslabel(file, argp);
5537 case BTRFS_IOC_SET_FSLABEL: 5455 case BTRFS_IOC_SET_FSLABEL:
5538 return btrfs_ioctl_set_fslabel(file, argp); 5456 return btrfs_ioctl_set_fslabel(file, argp);
5539 case BTRFS_IOC_FILE_EXTENT_SAME:
5540 return btrfs_ioctl_file_extent_same(file, argp);
5541 case BTRFS_IOC_GET_SUPPORTED_FEATURES: 5457 case BTRFS_IOC_GET_SUPPORTED_FEATURES:
5542 return btrfs_ioctl_get_supported_features(file, argp); 5458 return btrfs_ioctl_get_supported_features(file, argp);
5543 case BTRFS_IOC_GET_FEATURES: 5459 case BTRFS_IOC_GET_FEATURES: