Commit cbf8b8ca authored by Mark Fasheh's avatar Mark Fasheh Committed by Chris Mason

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: default avatarMark Fasheh <mfasheh@suse.de>
Signed-off-by: default avatarJosef Bacik <jbacik@fusionio.com>
Signed-off-by: default avatarChris Mason <chris.mason@fusionio.com>
parent 93fd63c2
...@@ -2696,9 +2696,9 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 len, ...@@ -2696,9 +2696,9 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 len,
static long btrfs_ioctl_file_extent_same(struct file *file, static long btrfs_ioctl_file_extent_same(struct file *file,
void __user *argp) void __user *argp)
{ {
struct btrfs_ioctl_same_args *args = argp; struct btrfs_ioctl_same_args tmp;
struct btrfs_ioctl_same_args same; struct btrfs_ioctl_same_args *same;
struct btrfs_ioctl_same_extent_info info; struct btrfs_ioctl_same_extent_info *info;
struct inode *src = file->f_dentry->d_inode; struct inode *src = file->f_dentry->d_inode;
struct file *dst_file = NULL; struct file *dst_file = NULL;
struct inode *dst; struct inode *dst;
...@@ -2706,6 +2706,7 @@ static long btrfs_ioctl_file_extent_same(struct file *file, ...@@ -2706,6 +2706,7 @@ static long btrfs_ioctl_file_extent_same(struct file *file,
u64 len; u64 len;
int i; int i;
int ret; int ret;
unsigned long size;
u64 bs = BTRFS_I(src)->root->fs_info->sb->s_blocksize; u64 bs = BTRFS_I(src)->root->fs_info->sb->s_blocksize;
bool is_admin = capable(CAP_SYS_ADMIN); bool is_admin = capable(CAP_SYS_ADMIN);
...@@ -2716,15 +2717,30 @@ static long btrfs_ioctl_file_extent_same(struct file *file, ...@@ -2716,15 +2717,30 @@ static long btrfs_ioctl_file_extent_same(struct file *file,
if (ret) if (ret)
return ret; return ret;
if (copy_from_user(&same, if (copy_from_user(&tmp,
(struct btrfs_ioctl_same_args __user *)argp, (struct btrfs_ioctl_same_args __user *)argp,
sizeof(same))) { sizeof(tmp))) {
ret = -EFAULT; ret = -EFAULT;
goto out; goto out;
} }
off = same.logical_offset; size = sizeof(tmp) +
len = same.length; tmp.dest_count * sizeof(struct btrfs_ioctl_same_extent_info);
same = kmalloc(size, GFP_NOFS);
if (!same) {
ret = -EFAULT;
goto out;
}
if (copy_from_user(same,
(struct btrfs_ioctl_same_args __user *)argp, size)) {
ret = -EFAULT;
goto out;
}
off = same->logical_offset;
len = same->length;
/* /*
* Limit the total length we will dedupe for each operation. * Limit the total length we will dedupe for each operation.
...@@ -2752,27 +2768,28 @@ static long btrfs_ioctl_file_extent_same(struct file *file, ...@@ -2752,27 +2768,28 @@ static long btrfs_ioctl_file_extent_same(struct file *file,
if (!S_ISREG(src->i_mode)) if (!S_ISREG(src->i_mode))
goto out; goto out;
ret = 0; /* pre-format output fields to sane values */
for (i = 0; i < same.dest_count; i++) { for (i = 0; i < same->dest_count; i++) {
if (copy_from_user(&info, &args->info[i], sizeof(info))) { same->info[i].bytes_deduped = 0ULL;
ret = -EFAULT; same->info[i].status = 0;
goto out; }
}
info.bytes_deduped = 0; ret = 0;
for (i = 0; i < same->dest_count; i++) {
info = &same->info[i];
dst_file = fget(info.fd); dst_file = fget(info->fd);
if (!dst_file) { if (!dst_file) {
info.status = -EBADF; info->status = -EBADF;
goto next; goto next;
} }
if (!(is_admin || (dst_file->f_mode & FMODE_WRITE))) { if (!(is_admin || (dst_file->f_mode & FMODE_WRITE))) {
info.status = -EINVAL; info->status = -EINVAL;
goto next; goto next;
} }
info.status = -EXDEV; info->status = -EXDEV;
if (file->f_path.mnt != dst_file->f_path.mnt) if (file->f_path.mnt != dst_file->f_path.mnt)
goto next; goto next;
...@@ -2781,32 +2798,29 @@ static long btrfs_ioctl_file_extent_same(struct file *file, ...@@ -2781,32 +2798,29 @@ static long btrfs_ioctl_file_extent_same(struct file *file,
goto next; goto next;
if (S_ISDIR(dst->i_mode)) { if (S_ISDIR(dst->i_mode)) {
info.status = -EISDIR; info->status = -EISDIR;
goto next; goto next;
} }
if (!S_ISREG(dst->i_mode)) { if (!S_ISREG(dst->i_mode)) {
info.status = -EACCES; info->status = -EACCES;
goto next; goto next;
} }
info.status = btrfs_extent_same(src, off, len, dst, info->status = btrfs_extent_same(src, off, len, dst,
info.logical_offset); info->logical_offset);
if (info.status == 0) if (info->status == 0)
info.bytes_deduped += len; info->bytes_deduped += len;
next: next:
if (dst_file) if (dst_file)
fput(dst_file); fput(dst_file);
if (__put_user_unaligned(info.status, &args->info[i].status) ||
__put_user_unaligned(info.bytes_deduped,
&args->info[i].bytes_deduped)) {
ret = -EFAULT;
goto out;
}
} }
ret = copy_to_user(argp, same, size);
if (ret)
ret = -EFAULT;
out: out:
mnt_drop_write_file(file); mnt_drop_write_file(file);
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment