diff options
author | Darrick J. Wong <darrick.wong@oracle.com> | 2018-10-29 19:44:45 -0400 |
---|---|---|
committer | Dave Chinner <david@fromorbit.com> | 2018-10-29 19:44:45 -0400 |
commit | 900611a1bd06ef4a79980e58babc61ef056c81ab (patch) | |
tree | 1d1d62cc0bf025f450cae70d2e5f278d089eb0e3 | |
parent | a8a94302c9754d05069ee149cf01df8aa5116aaa (diff) |
ocfs2: support partial clone range and dedupe range
Change the ocfs2 remap code to allow for returning partial results.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
-rw-r--r-- | fs/ocfs2/file.c | 7 | ||||
-rw-r--r-- | fs/ocfs2/refcounttree.c | 72 | ||||
-rw-r--r-- | fs/ocfs2/refcounttree.h | 12 |
3 files changed, 46 insertions, 45 deletions
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index fbaeafe44b5f..8125c5ccf821 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
@@ -2531,14 +2531,11 @@ static loff_t ocfs2_remap_file_range(struct file *file_in, loff_t pos_in, | |||
2531 | struct file *file_out, loff_t pos_out, | 2531 | struct file *file_out, loff_t pos_out, |
2532 | loff_t len, unsigned int remap_flags) | 2532 | loff_t len, unsigned int remap_flags) |
2533 | { | 2533 | { |
2534 | int ret; | ||
2535 | |||
2536 | if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY)) | 2534 | if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY)) |
2537 | return -EINVAL; | 2535 | return -EINVAL; |
2538 | 2536 | ||
2539 | ret = ocfs2_reflink_remap_range(file_in, pos_in, file_out, pos_out, | 2537 | return ocfs2_reflink_remap_range(file_in, pos_in, file_out, pos_out, |
2540 | len, remap_flags); | 2538 | len, remap_flags); |
2541 | return ret < 0 ? ret : len; | ||
2542 | } | 2539 | } |
2543 | 2540 | ||
2544 | const struct inode_operations ocfs2_file_iops = { | 2541 | const struct inode_operations ocfs2_file_iops = { |
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index 7c709229e108..c7409578657b 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c | |||
@@ -4507,14 +4507,14 @@ out_commit: | |||
4507 | } | 4507 | } |
4508 | 4508 | ||
4509 | /* Remap the range pos_in:len in s_inode to pos_out:len in t_inode. */ | 4509 | /* Remap the range pos_in:len in s_inode to pos_out:len in t_inode. */ |
4510 | static int ocfs2_reflink_remap_extent(struct inode *s_inode, | 4510 | static loff_t ocfs2_reflink_remap_extent(struct inode *s_inode, |
4511 | struct buffer_head *s_bh, | 4511 | struct buffer_head *s_bh, |
4512 | loff_t pos_in, | 4512 | loff_t pos_in, |
4513 | struct inode *t_inode, | 4513 | struct inode *t_inode, |
4514 | struct buffer_head *t_bh, | 4514 | struct buffer_head *t_bh, |
4515 | loff_t pos_out, | 4515 | loff_t pos_out, |
4516 | loff_t len, | 4516 | loff_t len, |
4517 | struct ocfs2_cached_dealloc_ctxt *dealloc) | 4517 | struct ocfs2_cached_dealloc_ctxt *dealloc) |
4518 | { | 4518 | { |
4519 | struct ocfs2_extent_tree s_et; | 4519 | struct ocfs2_extent_tree s_et; |
4520 | struct ocfs2_extent_tree t_et; | 4520 | struct ocfs2_extent_tree t_et; |
@@ -4522,8 +4522,9 @@ static int ocfs2_reflink_remap_extent(struct inode *s_inode, | |||
4522 | struct buffer_head *ref_root_bh = NULL; | 4522 | struct buffer_head *ref_root_bh = NULL; |
4523 | struct ocfs2_refcount_tree *ref_tree; | 4523 | struct ocfs2_refcount_tree *ref_tree; |
4524 | struct ocfs2_super *osb; | 4524 | struct ocfs2_super *osb; |
4525 | loff_t remapped_bytes = 0; | ||
4525 | loff_t pstart, plen; | 4526 | loff_t pstart, plen; |
4526 | u32 p_cluster, num_clusters, slast, spos, tpos; | 4527 | u32 p_cluster, num_clusters, slast, spos, tpos, remapped_clus = 0; |
4527 | unsigned int ext_flags; | 4528 | unsigned int ext_flags; |
4528 | int ret = 0; | 4529 | int ret = 0; |
4529 | 4530 | ||
@@ -4605,30 +4606,34 @@ static int ocfs2_reflink_remap_extent(struct inode *s_inode, | |||
4605 | next_loop: | 4606 | next_loop: |
4606 | spos += num_clusters; | 4607 | spos += num_clusters; |
4607 | tpos += num_clusters; | 4608 | tpos += num_clusters; |
4609 | remapped_clus += num_clusters; | ||
4608 | } | 4610 | } |
4609 | 4611 | ||
4610 | out: | 4612 | goto out; |
4611 | return ret; | ||
4612 | out_unlock_refcount: | 4613 | out_unlock_refcount: |
4613 | ocfs2_unlock_refcount_tree(osb, ref_tree, 1); | 4614 | ocfs2_unlock_refcount_tree(osb, ref_tree, 1); |
4614 | brelse(ref_root_bh); | 4615 | brelse(ref_root_bh); |
4615 | return ret; | 4616 | out: |
4617 | remapped_bytes = ocfs2_clusters_to_bytes(t_inode->i_sb, remapped_clus); | ||
4618 | remapped_bytes = min_t(loff_t, len, remapped_bytes); | ||
4619 | |||
4620 | return remapped_bytes > 0 ? remapped_bytes : ret; | ||
4616 | } | 4621 | } |
4617 | 4622 | ||
4618 | /* Set up refcount tree and remap s_inode to t_inode. */ | 4623 | /* Set up refcount tree and remap s_inode to t_inode. */ |
4619 | static int ocfs2_reflink_remap_blocks(struct inode *s_inode, | 4624 | static loff_t ocfs2_reflink_remap_blocks(struct inode *s_inode, |
4620 | struct buffer_head *s_bh, | 4625 | struct buffer_head *s_bh, |
4621 | loff_t pos_in, | 4626 | loff_t pos_in, |
4622 | struct inode *t_inode, | 4627 | struct inode *t_inode, |
4623 | struct buffer_head *t_bh, | 4628 | struct buffer_head *t_bh, |
4624 | loff_t pos_out, | 4629 | loff_t pos_out, |
4625 | loff_t len) | 4630 | loff_t len) |
4626 | { | 4631 | { |
4627 | struct ocfs2_cached_dealloc_ctxt dealloc; | 4632 | struct ocfs2_cached_dealloc_ctxt dealloc; |
4628 | struct ocfs2_super *osb; | 4633 | struct ocfs2_super *osb; |
4629 | struct ocfs2_dinode *dis; | 4634 | struct ocfs2_dinode *dis; |
4630 | struct ocfs2_dinode *dit; | 4635 | struct ocfs2_dinode *dit; |
4631 | int ret; | 4636 | loff_t ret; |
4632 | 4637 | ||
4633 | osb = OCFS2_SB(s_inode->i_sb); | 4638 | osb = OCFS2_SB(s_inode->i_sb); |
4634 | dis = (struct ocfs2_dinode *)s_bh->b_data; | 4639 | dis = (struct ocfs2_dinode *)s_bh->b_data; |
@@ -4700,7 +4705,7 @@ static int ocfs2_reflink_remap_blocks(struct inode *s_inode, | |||
4700 | /* Actually remap extents now. */ | 4705 | /* Actually remap extents now. */ |
4701 | ret = ocfs2_reflink_remap_extent(s_inode, s_bh, pos_in, t_inode, t_bh, | 4706 | ret = ocfs2_reflink_remap_extent(s_inode, s_bh, pos_in, t_inode, t_bh, |
4702 | pos_out, len, &dealloc); | 4707 | pos_out, len, &dealloc); |
4703 | if (ret) { | 4708 | if (ret < 0) { |
4704 | mlog_errno(ret); | 4709 | mlog_errno(ret); |
4705 | goto out; | 4710 | goto out; |
4706 | } | 4711 | } |
@@ -4820,18 +4825,19 @@ static void ocfs2_reflink_inodes_unlock(struct inode *s_inode, | |||
4820 | } | 4825 | } |
4821 | 4826 | ||
4822 | /* Link a range of blocks from one file to another. */ | 4827 | /* Link a range of blocks from one file to another. */ |
4823 | int ocfs2_reflink_remap_range(struct file *file_in, | 4828 | loff_t ocfs2_reflink_remap_range(struct file *file_in, |
4824 | loff_t pos_in, | 4829 | loff_t pos_in, |
4825 | struct file *file_out, | 4830 | struct file *file_out, |
4826 | loff_t pos_out, | 4831 | loff_t pos_out, |
4827 | loff_t len, | 4832 | loff_t len, |
4828 | unsigned int remap_flags) | 4833 | unsigned int remap_flags) |
4829 | { | 4834 | { |
4830 | struct inode *inode_in = file_inode(file_in); | 4835 | struct inode *inode_in = file_inode(file_in); |
4831 | struct inode *inode_out = file_inode(file_out); | 4836 | struct inode *inode_out = file_inode(file_out); |
4832 | struct ocfs2_super *osb = OCFS2_SB(inode_in->i_sb); | 4837 | struct ocfs2_super *osb = OCFS2_SB(inode_in->i_sb); |
4833 | struct buffer_head *in_bh = NULL, *out_bh = NULL; | 4838 | struct buffer_head *in_bh = NULL, *out_bh = NULL; |
4834 | bool same_inode = (inode_in == inode_out); | 4839 | bool same_inode = (inode_in == inode_out); |
4840 | loff_t remapped = 0; | ||
4835 | ssize_t ret; | 4841 | ssize_t ret; |
4836 | 4842 | ||
4837 | if (!ocfs2_refcount_tree(osb)) | 4843 | if (!ocfs2_refcount_tree(osb)) |
@@ -4866,12 +4872,13 @@ int ocfs2_reflink_remap_range(struct file *file_in, | |||
4866 | round_down(pos_out, PAGE_SIZE), | 4872 | round_down(pos_out, PAGE_SIZE), |
4867 | round_up(pos_out + len, PAGE_SIZE) - 1); | 4873 | round_up(pos_out + len, PAGE_SIZE) - 1); |
4868 | 4874 | ||
4869 | ret = ocfs2_reflink_remap_blocks(inode_in, in_bh, pos_in, inode_out, | 4875 | remapped = ocfs2_reflink_remap_blocks(inode_in, in_bh, pos_in, |
4870 | out_bh, pos_out, len); | 4876 | inode_out, out_bh, pos_out, len); |
4871 | up_write(&OCFS2_I(inode_in)->ip_alloc_sem); | 4877 | up_write(&OCFS2_I(inode_in)->ip_alloc_sem); |
4872 | if (!same_inode) | 4878 | if (!same_inode) |
4873 | up_write(&OCFS2_I(inode_out)->ip_alloc_sem); | 4879 | up_write(&OCFS2_I(inode_out)->ip_alloc_sem); |
4874 | if (ret) { | 4880 | if (remapped < 0) { |
4881 | ret = remapped; | ||
4875 | mlog_errno(ret); | 4882 | mlog_errno(ret); |
4876 | goto out_unlock; | 4883 | goto out_unlock; |
4877 | } | 4884 | } |
@@ -4889,10 +4896,7 @@ int ocfs2_reflink_remap_range(struct file *file_in, | |||
4889 | goto out_unlock; | 4896 | goto out_unlock; |
4890 | } | 4897 | } |
4891 | 4898 | ||
4892 | ocfs2_reflink_inodes_unlock(inode_in, in_bh, inode_out, out_bh); | ||
4893 | return 0; | ||
4894 | |||
4895 | out_unlock: | 4899 | out_unlock: |
4896 | ocfs2_reflink_inodes_unlock(inode_in, in_bh, inode_out, out_bh); | 4900 | ocfs2_reflink_inodes_unlock(inode_in, in_bh, inode_out, out_bh); |
4897 | return ret; | 4901 | return remapped > 0 ? remapped : ret; |
4898 | } | 4902 | } |
diff --git a/fs/ocfs2/refcounttree.h b/fs/ocfs2/refcounttree.h index eb65c1d0843c..9e64daba395d 100644 --- a/fs/ocfs2/refcounttree.h +++ b/fs/ocfs2/refcounttree.h | |||
@@ -115,11 +115,11 @@ int ocfs2_reflink_ioctl(struct inode *inode, | |||
115 | const char __user *oldname, | 115 | const char __user *oldname, |
116 | const char __user *newname, | 116 | const char __user *newname, |
117 | bool preserve); | 117 | bool preserve); |
118 | int ocfs2_reflink_remap_range(struct file *file_in, | 118 | loff_t ocfs2_reflink_remap_range(struct file *file_in, |
119 | loff_t pos_in, | 119 | loff_t pos_in, |
120 | struct file *file_out, | 120 | struct file *file_out, |
121 | loff_t pos_out, | 121 | loff_t pos_out, |
122 | loff_t len, | 122 | loff_t len, |
123 | unsigned int remap_flags); | 123 | unsigned int remap_flags); |
124 | 124 | ||
125 | #endif /* OCFS2_REFCOUNTTREE_H */ | 125 | #endif /* OCFS2_REFCOUNTTREE_H */ |