aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorMark Fasheh <mfasheh@suse.de>2013-09-17 18:43:54 -0400
committerChris Mason <chris.mason@fusionio.com>2013-09-21 11:05:31 -0400
commitcbf8b8ca3ec799c11a4cbb29d812d84adf2990b0 (patch)
treefc3165c1469f1d201123cf579964f33bbe4b65a6 /fs/btrfs
parent93fd63c2f001ca6797c6b15b696a484b165b4800 (diff)
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 <mfasheh@suse.de> Signed-off-by: Josef Bacik <jbacik@fusionio.com> Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/ioctl.c76
1 files changed, 45 insertions, 31 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index fba259ab9994..9d46f60cb943 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2696,9 +2696,9 @@ out_unlock:
2696static long btrfs_ioctl_file_extent_same(struct file *file, 2696static long btrfs_ioctl_file_extent_same(struct file *file,
2697 void __user *argp) 2697 void __user *argp)
2698{ 2698{
2699 struct btrfs_ioctl_same_args *args = argp; 2699 struct btrfs_ioctl_same_args tmp;
2700 struct btrfs_ioctl_same_args same; 2700 struct btrfs_ioctl_same_args *same;
2701 struct btrfs_ioctl_same_extent_info info; 2701 struct btrfs_ioctl_same_extent_info *info;
2702 struct inode *src = file->f_dentry->d_inode; 2702 struct inode *src = file->f_dentry->d_inode;
2703 struct file *dst_file = NULL; 2703 struct file *dst_file = NULL;
2704 struct inode *dst; 2704 struct inode *dst;
@@ -2706,6 +2706,7 @@ static long btrfs_ioctl_file_extent_same(struct file *file,
2706 u64 len; 2706 u64 len;
2707 int i; 2707 int i;
2708 int ret; 2708 int ret;
2709 unsigned long size;
2709 u64 bs = BTRFS_I(src)->root->fs_info->sb->s_blocksize; 2710 u64 bs = BTRFS_I(src)->root->fs_info->sb->s_blocksize;
2710 bool is_admin = capable(CAP_SYS_ADMIN); 2711 bool is_admin = capable(CAP_SYS_ADMIN);
2711 2712
@@ -2716,15 +2717,30 @@ static long btrfs_ioctl_file_extent_same(struct file *file,
2716 if (ret) 2717 if (ret)
2717 return ret; 2718 return ret;
2718 2719
2719 if (copy_from_user(&same, 2720 if (copy_from_user(&tmp,
2720 (struct btrfs_ioctl_same_args __user *)argp, 2721 (struct btrfs_ioctl_same_args __user *)argp,
2721 sizeof(same))) { 2722 sizeof(tmp))) {
2722 ret = -EFAULT; 2723 ret = -EFAULT;
2723 goto out; 2724 goto out;
2724 } 2725 }
2725 2726
2726 off = same.logical_offset; 2727 size = sizeof(tmp) +
2727 len = same.length; 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;
2728 2744
2729 /* 2745 /*
2730 * Limit the total length we will dedupe for each operation. 2746 * 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 if (!S_ISREG(src->i_mode)) 2768 if (!S_ISREG(src->i_mode))
2753 goto out; 2769 goto out;
2754 2770
2755 ret = 0; 2771 /* pre-format output fields to sane values */
2756 for (i = 0; i < same.dest_count; i++) { 2772 for (i = 0; i < same->dest_count; i++) {
2757 if (copy_from_user(&info, &args->info[i], sizeof(info))) { 2773 same->info[i].bytes_deduped = 0ULL;
2758 ret = -EFAULT; 2774 same->info[i].status = 0;
2759 goto out; 2775 }
2760 }
2761 2776
2762 info.bytes_deduped = 0; 2777 ret = 0;
2778 for (i = 0; i < same->dest_count; i++) {
2779 info = &same->info[i];
2763 2780
2764 dst_file = fget(info.fd); 2781 dst_file = fget(info->fd);
2765 if (!dst_file) { 2782 if (!dst_file) {
2766 info.status = -EBADF; 2783 info->status = -EBADF;
2767 goto next; 2784 goto next;
2768 } 2785 }
2769 2786
2770 if (!(is_admin || (dst_file->f_mode & FMODE_WRITE))) { 2787 if (!(is_admin || (dst_file->f_mode & FMODE_WRITE))) {
2771 info.status = -EINVAL; 2788 info->status = -EINVAL;
2772 goto next; 2789 goto next;
2773 } 2790 }
2774 2791
2775 info.status = -EXDEV; 2792 info->status = -EXDEV;
2776 if (file->f_path.mnt != dst_file->f_path.mnt) 2793 if (file->f_path.mnt != dst_file->f_path.mnt)
2777 goto next; 2794 goto next;
2778 2795
@@ -2781,32 +2798,29 @@ static long btrfs_ioctl_file_extent_same(struct file *file,
2781 goto next; 2798 goto next;
2782 2799
2783 if (S_ISDIR(dst->i_mode)) { 2800 if (S_ISDIR(dst->i_mode)) {
2784 info.status = -EISDIR; 2801 info->status = -EISDIR;
2785 goto next; 2802 goto next;
2786 } 2803 }
2787 2804
2788 if (!S_ISREG(dst->i_mode)) { 2805 if (!S_ISREG(dst->i_mode)) {
2789 info.status = -EACCES; 2806 info->status = -EACCES;
2790 goto next; 2807 goto next;
2791 } 2808 }
2792 2809
2793 info.status = btrfs_extent_same(src, off, len, dst, 2810 info->status = btrfs_extent_same(src, off, len, dst,
2794 info.logical_offset); 2811 info->logical_offset);
2795 if (info.status == 0) 2812 if (info->status == 0)
2796 info.bytes_deduped += len; 2813 info->bytes_deduped += len;
2797 2814
2798next: 2815next:
2799 if (dst_file) 2816 if (dst_file)
2800 fput(dst_file); 2817 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 }
2808 } 2818 }
2809 2819
2820 ret = copy_to_user(argp, same, size);
2821 if (ret)
2822 ret = -EFAULT;
2823
2810out: 2824out:
2811 mnt_drop_write_file(file); 2825 mnt_drop_write_file(file);
2812 return ret; 2826 return ret;