Skip to content

Commit cbf8b8c

Browse files
Mark FashehChris Mason
authored andcommitted
btrfs: change extent-same to copy entire argument struct
btrfs_ioctl_file_extent_same() uses __put_user_unaligned() to copy some data back to it's argument struct. Unfortunately, not all architectures provide __put_user_unaligned(), so compiles break on them if btrfs is selected. Instead, just copy the whole struct in / out at the start and end of operations, respectively. Signed-off-by: Mark Fasheh <[email protected]> Signed-off-by: Josef Bacik <[email protected]> Signed-off-by: Chris Mason <[email protected]>
1 parent 93fd63c commit cbf8b8c

File tree

1 file changed

+45
-31
lines changed

1 file changed

+45
-31
lines changed

fs/btrfs/ioctl.c

Lines changed: 45 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2696,16 +2696,17 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 len,
26962696
static long btrfs_ioctl_file_extent_same(struct file *file,
26972697
void __user *argp)
26982698
{
2699-
struct btrfs_ioctl_same_args *args = argp;
2700-
struct btrfs_ioctl_same_args same;
2701-
struct btrfs_ioctl_same_extent_info info;
2699+
struct btrfs_ioctl_same_args tmp;
2700+
struct btrfs_ioctl_same_args *same;
2701+
struct btrfs_ioctl_same_extent_info *info;
27022702
struct inode *src = file->f_dentry->d_inode;
27032703
struct file *dst_file = NULL;
27042704
struct inode *dst;
27052705
u64 off;
27062706
u64 len;
27072707
int i;
27082708
int ret;
2709+
unsigned long size;
27092710
u64 bs = BTRFS_I(src)->root->fs_info->sb->s_blocksize;
27102711
bool is_admin = capable(CAP_SYS_ADMIN);
27112712

@@ -2716,15 +2717,30 @@ static long btrfs_ioctl_file_extent_same(struct file *file,
27162717
if (ret)
27172718
return ret;
27182719

2719-
if (copy_from_user(&same,
2720+
if (copy_from_user(&tmp,
27202721
(struct btrfs_ioctl_same_args __user *)argp,
2721-
sizeof(same))) {
2722+
sizeof(tmp))) {
27222723
ret = -EFAULT;
27232724
goto out;
27242725
}
27252726

2726-
off = same.logical_offset;
2727-
len = same.length;
2727+
size = sizeof(tmp) +
2728+
tmp.dest_count * sizeof(struct btrfs_ioctl_same_extent_info);
2729+
2730+
same = kmalloc(size, GFP_NOFS);
2731+
if (!same) {
2732+
ret = -EFAULT;
2733+
goto out;
2734+
}
2735+
2736+
if (copy_from_user(same,
2737+
(struct btrfs_ioctl_same_args __user *)argp, size)) {
2738+
ret = -EFAULT;
2739+
goto out;
2740+
}
2741+
2742+
off = same->logical_offset;
2743+
len = same->length;
27282744

27292745
/*
27302746
* Limit the total length we will dedupe for each operation.
@@ -2752,27 +2768,28 @@ static long btrfs_ioctl_file_extent_same(struct file *file,
27522768
if (!S_ISREG(src->i_mode))
27532769
goto out;
27542770

2755-
ret = 0;
2756-
for (i = 0; i < same.dest_count; i++) {
2757-
if (copy_from_user(&info, &args->info[i], sizeof(info))) {
2758-
ret = -EFAULT;
2759-
goto out;
2760-
}
2771+
/* pre-format output fields to sane values */
2772+
for (i = 0; i < same->dest_count; i++) {
2773+
same->info[i].bytes_deduped = 0ULL;
2774+
same->info[i].status = 0;
2775+
}
27612776

2762-
info.bytes_deduped = 0;
2777+
ret = 0;
2778+
for (i = 0; i < same->dest_count; i++) {
2779+
info = &same->info[i];
27632780

2764-
dst_file = fget(info.fd);
2781+
dst_file = fget(info->fd);
27652782
if (!dst_file) {
2766-
info.status = -EBADF;
2783+
info->status = -EBADF;
27672784
goto next;
27682785
}
27692786

27702787
if (!(is_admin || (dst_file->f_mode & FMODE_WRITE))) {
2771-
info.status = -EINVAL;
2788+
info->status = -EINVAL;
27722789
goto next;
27732790
}
27742791

2775-
info.status = -EXDEV;
2792+
info->status = -EXDEV;
27762793
if (file->f_path.mnt != dst_file->f_path.mnt)
27772794
goto next;
27782795

@@ -2781,32 +2798,29 @@ static long btrfs_ioctl_file_extent_same(struct file *file,
27812798
goto next;
27822799

27832800
if (S_ISDIR(dst->i_mode)) {
2784-
info.status = -EISDIR;
2801+
info->status = -EISDIR;
27852802
goto next;
27862803
}
27872804

27882805
if (!S_ISREG(dst->i_mode)) {
2789-
info.status = -EACCES;
2806+
info->status = -EACCES;
27902807
goto next;
27912808
}
27922809

2793-
info.status = btrfs_extent_same(src, off, len, dst,
2794-
info.logical_offset);
2795-
if (info.status == 0)
2796-
info.bytes_deduped += len;
2810+
info->status = btrfs_extent_same(src, off, len, dst,
2811+
info->logical_offset);
2812+
if (info->status == 0)
2813+
info->bytes_deduped += len;
27972814

27982815
next:
27992816
if (dst_file)
28002817
fput(dst_file);
2801-
2802-
if (__put_user_unaligned(info.status, &args->info[i].status) ||
2803-
__put_user_unaligned(info.bytes_deduped,
2804-
&args->info[i].bytes_deduped)) {
2805-
ret = -EFAULT;
2806-
goto out;
2807-
}
28082818
}
28092819

2820+
ret = copy_to_user(argp, same, size);
2821+
if (ret)
2822+
ret = -EFAULT;
2823+
28102824
out:
28112825
mnt_drop_write_file(file);
28122826
return ret;

0 commit comments

Comments
 (0)