@@ -2696,16 +2696,17 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 len,
2696
2696
static long btrfs_ioctl_file_extent_same (struct file * file ,
2697
2697
void __user * argp )
2698
2698
{
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 ;
2702
2702
struct inode * src = file -> f_dentry -> d_inode ;
2703
2703
struct file * dst_file = NULL ;
2704
2704
struct inode * dst ;
2705
2705
u64 off ;
2706
2706
u64 len ;
2707
2707
int i ;
2708
2708
int ret ;
2709
+ unsigned long size ;
2709
2710
u64 bs = BTRFS_I (src )-> root -> fs_info -> sb -> s_blocksize ;
2710
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
2717
if (ret )
2717
2718
return ret ;
2718
2719
2719
- if (copy_from_user (& same ,
2720
+ if (copy_from_user (& tmp ,
2720
2721
(struct btrfs_ioctl_same_args __user * )argp ,
2721
- sizeof (same ))) {
2722
+ sizeof (tmp ))) {
2722
2723
ret = - EFAULT ;
2723
2724
goto out ;
2724
2725
}
2725
2726
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 ;
2728
2744
2729
2745
/*
2730
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
2768
if (!S_ISREG (src -> i_mode ))
2753
2769
goto out ;
2754
2770
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
+ }
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
2782
if (!dst_file ) {
2766
- info . status = - EBADF ;
2783
+ info -> status = - EBADF ;
2767
2784
goto next ;
2768
2785
}
2769
2786
2770
2787
if (!(is_admin || (dst_file -> f_mode & FMODE_WRITE ))) {
2771
- info . status = - EINVAL ;
2788
+ info -> status = - EINVAL ;
2772
2789
goto next ;
2773
2790
}
2774
2791
2775
- info . status = - EXDEV ;
2792
+ info -> status = - EXDEV ;
2776
2793
if (file -> f_path .mnt != dst_file -> f_path .mnt )
2777
2794
goto next ;
2778
2795
@@ -2781,32 +2798,29 @@ static long btrfs_ioctl_file_extent_same(struct file *file,
2781
2798
goto next ;
2782
2799
2783
2800
if (S_ISDIR (dst -> i_mode )) {
2784
- info . status = - EISDIR ;
2801
+ info -> status = - EISDIR ;
2785
2802
goto next ;
2786
2803
}
2787
2804
2788
2805
if (!S_ISREG (dst -> i_mode )) {
2789
- info . status = - EACCES ;
2806
+ info -> status = - EACCES ;
2790
2807
goto next ;
2791
2808
}
2792
2809
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 ;
2797
2814
2798
2815
next :
2799
2816
if (dst_file )
2800
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
+
2810
2824
out :
2811
2825
mnt_drop_write_file (file );
2812
2826
return ret ;
0 commit comments