Skip to content

Commit 32b7c68

Browse files
Mark FashehChris Mason
authored andcommitted
btrfs_ioctl_clone: Move clone code into it's own function
There's some 250+ lines here that are easily encapsulated into their own function. I don't change how anything works here, just create and document the new btrfs_clone() function from btrfs_ioctl_clone() code. Signed-off-by: Mark Fasheh <[email protected]> Signed-off-by: Josef Bacik <[email protected]> Signed-off-by: Chris Mason <[email protected]>
1 parent 77fe20d commit 32b7c68

File tree

1 file changed

+139
-115
lines changed

1 file changed

+139
-115
lines changed

fs/btrfs/ioctl.c

Lines changed: 139 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -2490,136 +2490,43 @@ static inline void lock_extent_range(struct inode *inode, u64 off, u64 len)
24902490
}
24912491
}
24922492

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)
24952506
{
2496-
struct inode *inode = file_inode(file);
24972507
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;
25022509
struct extent_buffer *leaf;
2503-
char *buf;
2510+
struct btrfs_trans_handle *trans;
2511+
char *buf = NULL;
25042512
struct btrfs_key key;
25052513
u32 nritems;
25062514
int slot;
25072515
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;
25652517

25662518
ret = -ENOMEM;
25672519
buf = vmalloc(btrfs_level_size(root, 0));
25682520
if (!buf)
2569-
goto out_fput;
2521+
return ret;
25702522

25712523
path = btrfs_alloc_path();
25722524
if (!path) {
25732525
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;
26152527
}
26162528

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;
26232530
/* clone data */
26242531
key.objectid = btrfs_ino(src);
26252532
key.type = BTRFS_EXTENT_DATA_KEY;
@@ -2865,15 +2772,132 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
28652772
key.offset++;
28662773
}
28672774
ret = 0;
2775+
28682776
out:
28692777
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+
28702896
unlock_extent(&BTRFS_I(src)->io_tree, off, off + len - 1);
28712897
out_unlock:
28722898
mutex_unlock(&src->i_mutex);
28732899
if (!same_inode)
28742900
mutex_unlock(&inode->i_mutex);
2875-
vfree(buf);
2876-
btrfs_free_path(path);
28772901
out_fput:
28782902
fdput(src_file);
28792903
out_drop_write:

0 commit comments

Comments
 (0)