Commit 29ac8e85 authored by Darrick J. Wong's avatar Darrick J. Wong

ocfs2: implement the VFS clone_range, copy_range, and dedupe_range features

Connect the new VFS clone_range, copy_range, and dedupe_range features
to the existing reflink capability of ocfs2.  Compared to the existing
ocfs2 reflink ioctl We have to do things a little differently to support
the VFS semantics (we can clone subranges of a file but we don't clone
xattrs), but the VFS ioctls are more broadly supported.
Signed-off-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
---
v2: Convert inline data files to extents files before reflinking,
and fix i_blocks so that stat(2) output is correct.
v3: Make zero-length dedupe consistent with btrfs behavior.
v4: Use VFS double-inode lock routines and remove MAX_DEDUPE_LEN.
parent 86e59436
...@@ -1667,9 +1667,9 @@ static void ocfs2_calc_trunc_pos(struct inode *inode, ...@@ -1667,9 +1667,9 @@ static void ocfs2_calc_trunc_pos(struct inode *inode,
*done = ret; *done = ret;
} }
static int ocfs2_remove_inode_range(struct inode *inode, int ocfs2_remove_inode_range(struct inode *inode,
struct buffer_head *di_bh, u64 byte_start, struct buffer_head *di_bh, u64 byte_start,
u64 byte_len) u64 byte_len)
{ {
int ret = 0, flags = 0, done = 0, i; int ret = 0, flags = 0, done = 0, i;
u32 trunc_start, trunc_len, trunc_end, trunc_cpos, phys_cpos; u32 trunc_start, trunc_len, trunc_end, trunc_cpos, phys_cpos;
...@@ -2439,6 +2439,31 @@ static loff_t ocfs2_file_llseek(struct file *file, loff_t offset, int whence) ...@@ -2439,6 +2439,31 @@ static loff_t ocfs2_file_llseek(struct file *file, loff_t offset, int whence)
return offset; return offset;
} }
static int ocfs2_file_clone_range(struct file *file_in,
loff_t pos_in,
struct file *file_out,
loff_t pos_out,
u64 len)
{
return ocfs2_reflink_remap_range(file_in, pos_in, file_out, pos_out,
len, false);
}
static ssize_t ocfs2_file_dedupe_range(struct file *src_file,
u64 loff,
u64 len,
struct file *dst_file,
u64 dst_loff)
{
int error;
error = ocfs2_reflink_remap_range(src_file, loff, dst_file, dst_loff,
len, true);
if (error)
return error;
return len;
}
const struct inode_operations ocfs2_file_iops = { const struct inode_operations ocfs2_file_iops = {
.setattr = ocfs2_setattr, .setattr = ocfs2_setattr,
.getattr = ocfs2_getattr, .getattr = ocfs2_getattr,
...@@ -2478,6 +2503,8 @@ const struct file_operations ocfs2_fops = { ...@@ -2478,6 +2503,8 @@ const struct file_operations ocfs2_fops = {
.splice_read = generic_file_splice_read, .splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write, .splice_write = iter_file_splice_write,
.fallocate = ocfs2_fallocate, .fallocate = ocfs2_fallocate,
.clone_file_range = ocfs2_file_clone_range,
.dedupe_file_range = ocfs2_file_dedupe_range,
}; };
const struct file_operations ocfs2_dops = { const struct file_operations ocfs2_dops = {
...@@ -2523,6 +2550,8 @@ const struct file_operations ocfs2_fops_no_plocks = { ...@@ -2523,6 +2550,8 @@ const struct file_operations ocfs2_fops_no_plocks = {
.splice_read = generic_file_splice_read, .splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write, .splice_write = iter_file_splice_write,
.fallocate = ocfs2_fallocate, .fallocate = ocfs2_fallocate,
.clone_file_range = ocfs2_file_clone_range,
.dedupe_file_range = ocfs2_file_dedupe_range,
}; };
const struct file_operations ocfs2_dops_no_plocks = { const struct file_operations ocfs2_dops_no_plocks = {
......
...@@ -82,4 +82,7 @@ int ocfs2_change_file_space(struct file *file, unsigned int cmd, ...@@ -82,4 +82,7 @@ int ocfs2_change_file_space(struct file *file, unsigned int cmd,
int ocfs2_check_range_for_refcount(struct inode *inode, loff_t pos, int ocfs2_check_range_for_refcount(struct inode *inode, loff_t pos,
size_t count); size_t count);
int ocfs2_remove_inode_range(struct inode *inode,
struct buffer_head *di_bh, u64 byte_start,
u64 byte_len);
#endif /* OCFS2_FILE_H */ #endif /* OCFS2_FILE_H */
This diff is collapsed.
...@@ -115,4 +115,11 @@ int ocfs2_reflink_ioctl(struct inode *inode, ...@@ -115,4 +115,11 @@ int ocfs2_reflink_ioctl(struct inode *inode,
const char __user *oldname, const char __user *oldname,
const char __user *newname, const char __user *newname,
bool preserve); bool preserve);
int ocfs2_reflink_remap_range(struct file *file_in,
loff_t pos_in,
struct file *file_out,
loff_t pos_out,
u64 len,
bool is_dedupe);
#endif /* OCFS2_REFCOUNTTREE_H */ #endif /* OCFS2_REFCOUNTTREE_H */
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