@@ -2490,136 +2490,43 @@ static inline void lock_extent_range(struct inode *inode, u64 off, u64 len)
2490
2490
}
2491
2491
}
2492
2492
2493
- static noinline long btrfs_ioctl_clone (struct file * file , unsigned long srcfd ,
2494
- u64 off , u64 olen , u64 destoff )
2493
+ /**
2494
+ * btrfs_clone() - clone a range from inode file to another
2495
+ *
2496
+ * @src: Inode to clone from
2497
+ * @inode: Inode to clone to
2498
+ * @off: Offset within source to start clone from
2499
+ * @olen: Original length, passed by user, of range to clone
2500
+ * @olen_aligned: Block-aligned value of olen, extent_same uses
2501
+ * identical values here
2502
+ * @destoff: Offset within @inode to start clone
2503
+ */
2504
+ static int btrfs_clone (struct inode * src , struct inode * inode ,
2505
+ u64 off , u64 olen , u64 olen_aligned , u64 destoff )
2495
2506
{
2496
- struct inode * inode = file_inode (file );
2497
2507
struct btrfs_root * root = BTRFS_I (inode )-> root ;
2498
- struct fd src_file ;
2499
- struct inode * src ;
2500
- struct btrfs_trans_handle * trans ;
2501
- struct btrfs_path * path ;
2508
+ struct btrfs_path * path = NULL ;
2502
2509
struct extent_buffer * leaf ;
2503
- char * buf ;
2510
+ struct btrfs_trans_handle * trans ;
2511
+ char * buf = NULL ;
2504
2512
struct btrfs_key key ;
2505
2513
u32 nritems ;
2506
2514
int slot ;
2507
2515
int ret ;
2508
- u64 len = olen ;
2509
- u64 bs = root -> fs_info -> sb -> s_blocksize ;
2510
- int same_inode = 0 ;
2511
-
2512
- /*
2513
- * TODO:
2514
- * - split compressed inline extents. annoying: we need to
2515
- * decompress into destination's address_space (the file offset
2516
- * may change, so source mapping won't do), then recompress (or
2517
- * otherwise reinsert) a subrange.
2518
- * - allow ranges within the same file to be cloned (provided
2519
- * they don't overlap)?
2520
- */
2521
-
2522
- /* the destination must be opened for writing */
2523
- if (!(file -> f_mode & FMODE_WRITE ) || (file -> f_flags & O_APPEND ))
2524
- return - EINVAL ;
2525
-
2526
- if (btrfs_root_readonly (root ))
2527
- return - EROFS ;
2528
-
2529
- ret = mnt_want_write_file (file );
2530
- if (ret )
2531
- return ret ;
2532
-
2533
- src_file = fdget (srcfd );
2534
- if (!src_file .file ) {
2535
- ret = - EBADF ;
2536
- goto out_drop_write ;
2537
- }
2538
-
2539
- ret = - EXDEV ;
2540
- if (src_file .file -> f_path .mnt != file -> f_path .mnt )
2541
- goto out_fput ;
2542
-
2543
- src = file_inode (src_file .file );
2544
-
2545
- ret = - EINVAL ;
2546
- if (src == inode )
2547
- same_inode = 1 ;
2548
-
2549
- /* the src must be open for reading */
2550
- if (!(src_file .file -> f_mode & FMODE_READ ))
2551
- goto out_fput ;
2552
-
2553
- /* don't make the dst file partly checksummed */
2554
- if ((BTRFS_I (src )-> flags & BTRFS_INODE_NODATASUM ) !=
2555
- (BTRFS_I (inode )-> flags & BTRFS_INODE_NODATASUM ))
2556
- goto out_fput ;
2557
-
2558
- ret = - EISDIR ;
2559
- if (S_ISDIR (src -> i_mode ) || S_ISDIR (inode -> i_mode ))
2560
- goto out_fput ;
2561
-
2562
- ret = - EXDEV ;
2563
- if (src -> i_sb != inode -> i_sb )
2564
- goto out_fput ;
2516
+ u64 len = olen_aligned ;
2565
2517
2566
2518
ret = - ENOMEM ;
2567
2519
buf = vmalloc (btrfs_level_size (root , 0 ));
2568
2520
if (!buf )
2569
- goto out_fput ;
2521
+ return ret ;
2570
2522
2571
2523
path = btrfs_alloc_path ();
2572
2524
if (!path ) {
2573
2525
vfree (buf );
2574
- goto out_fput ;
2575
- }
2576
- path -> reada = 2 ;
2577
-
2578
- if (!same_inode ) {
2579
- if (inode < src ) {
2580
- mutex_lock_nested (& inode -> i_mutex , I_MUTEX_PARENT );
2581
- mutex_lock_nested (& src -> i_mutex , I_MUTEX_CHILD );
2582
- } else {
2583
- mutex_lock_nested (& src -> i_mutex , I_MUTEX_PARENT );
2584
- mutex_lock_nested (& inode -> i_mutex , I_MUTEX_CHILD );
2585
- }
2586
- } else {
2587
- mutex_lock (& src -> i_mutex );
2588
- }
2589
-
2590
- /* determine range to clone */
2591
- ret = - EINVAL ;
2592
- if (off + len > src -> i_size || off + len < off )
2593
- goto out_unlock ;
2594
- if (len == 0 )
2595
- olen = len = src -> i_size - off ;
2596
- /* if we extend to eof, continue to block boundary */
2597
- if (off + len == src -> i_size )
2598
- len = ALIGN (src -> i_size , bs ) - off ;
2599
-
2600
- /* verify the end result is block aligned */
2601
- if (!IS_ALIGNED (off , bs ) || !IS_ALIGNED (off + len , bs ) ||
2602
- !IS_ALIGNED (destoff , bs ))
2603
- goto out_unlock ;
2604
-
2605
- /* verify if ranges are overlapped within the same file */
2606
- if (same_inode ) {
2607
- if (destoff + len > off && destoff < off + len )
2608
- goto out_unlock ;
2609
- }
2610
-
2611
- if (destoff > inode -> i_size ) {
2612
- ret = btrfs_cont_expand (inode , inode -> i_size , destoff );
2613
- if (ret )
2614
- goto out_unlock ;
2526
+ return ret ;
2615
2527
}
2616
2528
2617
- /* truncate page cache pages from target inode range */
2618
- truncate_inode_pages_range (& inode -> i_data , destoff ,
2619
- PAGE_CACHE_ALIGN (destoff + len ) - 1 );
2620
-
2621
- lock_extent_range (src , off , len );
2622
-
2529
+ path -> reada = 2 ;
2623
2530
/* clone data */
2624
2531
key .objectid = btrfs_ino (src );
2625
2532
key .type = BTRFS_EXTENT_DATA_KEY ;
@@ -2865,15 +2772,132 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
2865
2772
key .offset ++ ;
2866
2773
}
2867
2774
ret = 0 ;
2775
+
2868
2776
out :
2869
2777
btrfs_release_path (path );
2778
+ btrfs_free_path (path );
2779
+ vfree (buf );
2780
+ return ret ;
2781
+ }
2782
+
2783
+ static noinline long btrfs_ioctl_clone (struct file * file , unsigned long srcfd ,
2784
+ u64 off , u64 olen , u64 destoff )
2785
+ {
2786
+ struct inode * inode = fdentry (file )-> d_inode ;
2787
+ struct btrfs_root * root = BTRFS_I (inode )-> root ;
2788
+ struct fd src_file ;
2789
+ struct inode * src ;
2790
+ int ret ;
2791
+ u64 len = olen ;
2792
+ u64 bs = root -> fs_info -> sb -> s_blocksize ;
2793
+ int same_inode = 0 ;
2794
+
2795
+ /*
2796
+ * TODO:
2797
+ * - split compressed inline extents. annoying: we need to
2798
+ * decompress into destination's address_space (the file offset
2799
+ * may change, so source mapping won't do), then recompress (or
2800
+ * otherwise reinsert) a subrange.
2801
+ * - allow ranges within the same file to be cloned (provided
2802
+ * they don't overlap)?
2803
+ */
2804
+
2805
+ /* the destination must be opened for writing */
2806
+ if (!(file -> f_mode & FMODE_WRITE ) || (file -> f_flags & O_APPEND ))
2807
+ return - EINVAL ;
2808
+
2809
+ if (btrfs_root_readonly (root ))
2810
+ return - EROFS ;
2811
+
2812
+ ret = mnt_want_write_file (file );
2813
+ if (ret )
2814
+ return ret ;
2815
+
2816
+ src_file = fdget (srcfd );
2817
+ if (!src_file .file ) {
2818
+ ret = - EBADF ;
2819
+ goto out_drop_write ;
2820
+ }
2821
+
2822
+ ret = - EXDEV ;
2823
+ if (src_file .file -> f_path .mnt != file -> f_path .mnt )
2824
+ goto out_fput ;
2825
+
2826
+ src = file_inode (src_file .file );
2827
+
2828
+ ret = - EINVAL ;
2829
+ if (src == inode )
2830
+ same_inode = 1 ;
2831
+
2832
+ /* the src must be open for reading */
2833
+ if (!(src_file .file -> f_mode & FMODE_READ ))
2834
+ goto out_fput ;
2835
+
2836
+ /* don't make the dst file partly checksummed */
2837
+ if ((BTRFS_I (src )-> flags & BTRFS_INODE_NODATASUM ) !=
2838
+ (BTRFS_I (inode )-> flags & BTRFS_INODE_NODATASUM ))
2839
+ goto out_fput ;
2840
+
2841
+ ret = - EISDIR ;
2842
+ if (S_ISDIR (src -> i_mode ) || S_ISDIR (inode -> i_mode ))
2843
+ goto out_fput ;
2844
+
2845
+ ret = - EXDEV ;
2846
+ if (src -> i_sb != inode -> i_sb )
2847
+ goto out_fput ;
2848
+
2849
+ if (!same_inode ) {
2850
+ if (inode < src ) {
2851
+ mutex_lock_nested (& inode -> i_mutex , I_MUTEX_PARENT );
2852
+ mutex_lock_nested (& src -> i_mutex , I_MUTEX_CHILD );
2853
+ } else {
2854
+ mutex_lock_nested (& src -> i_mutex , I_MUTEX_PARENT );
2855
+ mutex_lock_nested (& inode -> i_mutex , I_MUTEX_CHILD );
2856
+ }
2857
+ } else {
2858
+ mutex_lock (& src -> i_mutex );
2859
+ }
2860
+
2861
+ /* determine range to clone */
2862
+ ret = - EINVAL ;
2863
+ if (off + len > src -> i_size || off + len < off )
2864
+ goto out_unlock ;
2865
+ if (len == 0 )
2866
+ olen = len = src -> i_size - off ;
2867
+ /* if we extend to eof, continue to block boundary */
2868
+ if (off + len == src -> i_size )
2869
+ len = ALIGN (src -> i_size , bs ) - off ;
2870
+
2871
+ /* verify the end result is block aligned */
2872
+ if (!IS_ALIGNED (off , bs ) || !IS_ALIGNED (off + len , bs ) ||
2873
+ !IS_ALIGNED (destoff , bs ))
2874
+ goto out_unlock ;
2875
+
2876
+ /* verify if ranges are overlapped within the same file */
2877
+ if (same_inode ) {
2878
+ if (destoff + len > off && destoff < off + len )
2879
+ goto out_unlock ;
2880
+ }
2881
+
2882
+ if (destoff > inode -> i_size ) {
2883
+ ret = btrfs_cont_expand (inode , inode -> i_size , destoff );
2884
+ if (ret )
2885
+ goto out_unlock ;
2886
+ }
2887
+
2888
+ /* truncate page cache pages from target inode range */
2889
+ truncate_inode_pages_range (& inode -> i_data , destoff ,
2890
+ PAGE_CACHE_ALIGN (destoff + len ) - 1 );
2891
+
2892
+ lock_extent_range (src , off , len );
2893
+
2894
+ ret = btrfs_clone (src , inode , off , olen , len , destoff );
2895
+
2870
2896
unlock_extent (& BTRFS_I (src )-> io_tree , off , off + len - 1 );
2871
2897
out_unlock :
2872
2898
mutex_unlock (& src -> i_mutex );
2873
2899
if (!same_inode )
2874
2900
mutex_unlock (& inode -> i_mutex );
2875
- vfree (buf );
2876
- btrfs_free_path (path );
2877
2901
out_fput :
2878
2902
fdput (src_file );
2879
2903
out_drop_write :
0 commit comments