diff options
author | Tao Ma <tao.ma@oracle.com> | 2009-08-17 23:43:55 -0400 |
---|---|---|
committer | Joel Becker <joel.becker@oracle.com> | 2009-09-22 23:09:45 -0400 |
commit | 2999d12f4d5529b282ce201b21444590c3f9f723 (patch) | |
tree | 9500f897753a59cf47e66af2cb7fd56c05ec8c1c /fs | |
parent | a7fe7a3a1ab5dac8d81e531c060f51e12010133b (diff) |
ocfs2: Add reflink support for xattr.
Signed-off-by: Tao Ma <tao.ma@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ocfs2/refcounttree.c | 24 | ||||
-rw-r--r-- | fs/ocfs2/refcounttree.h | 6 | ||||
-rw-r--r-- | fs/ocfs2/xattr.c | 923 | ||||
-rw-r--r-- | fs/ocfs2/xattr.h | 4 |
4 files changed, 945 insertions, 12 deletions
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index 5656c68a2cae..dc57d066f794 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c | |||
@@ -1894,12 +1894,12 @@ out: | |||
1894 | return ret; | 1894 | return ret; |
1895 | } | 1895 | } |
1896 | 1896 | ||
1897 | static int __ocfs2_increase_refcount(handle_t *handle, | 1897 | int ocfs2_increase_refcount(handle_t *handle, |
1898 | struct ocfs2_caching_info *ci, | 1898 | struct ocfs2_caching_info *ci, |
1899 | struct buffer_head *ref_root_bh, | 1899 | struct buffer_head *ref_root_bh, |
1900 | u64 cpos, u32 len, | 1900 | u64 cpos, u32 len, |
1901 | struct ocfs2_alloc_context *meta_ac, | 1901 | struct ocfs2_alloc_context *meta_ac, |
1902 | struct ocfs2_cached_dealloc_ctxt *dealloc) | 1902 | struct ocfs2_cached_dealloc_ctxt *dealloc) |
1903 | { | 1903 | { |
1904 | int ret = 0, index; | 1904 | int ret = 0, index; |
1905 | struct buffer_head *ref_leaf_bh = NULL; | 1905 | struct buffer_head *ref_leaf_bh = NULL; |
@@ -3631,9 +3631,9 @@ int ocfs2_add_refcount_flag(struct inode *inode, | |||
3631 | goto out_commit; | 3631 | goto out_commit; |
3632 | } | 3632 | } |
3633 | 3633 | ||
3634 | ret = __ocfs2_increase_refcount(handle, ref_ci, ref_root_bh, | 3634 | ret = ocfs2_increase_refcount(handle, ref_ci, ref_root_bh, |
3635 | p_cluster, num_clusters, | 3635 | p_cluster, num_clusters, |
3636 | meta_ac, dealloc); | 3636 | meta_ac, dealloc); |
3637 | if (ret) { | 3637 | if (ret) { |
3638 | mlog_errno(ret); | 3638 | mlog_errno(ret); |
3639 | goto out_commit; | 3639 | goto out_commit; |
@@ -3822,9 +3822,9 @@ static int ocfs2_add_refcounted_extent(struct inode *inode, | |||
3822 | goto out_commit; | 3822 | goto out_commit; |
3823 | } | 3823 | } |
3824 | 3824 | ||
3825 | ret = __ocfs2_increase_refcount(handle, ref_ci, ref_root_bh, | 3825 | ret = ocfs2_increase_refcount(handle, ref_ci, ref_root_bh, |
3826 | p_cluster, num_clusters, | 3826 | p_cluster, num_clusters, |
3827 | meta_ac, dealloc); | 3827 | meta_ac, dealloc); |
3828 | if (ret) | 3828 | if (ret) |
3829 | mlog_errno(ret); | 3829 | mlog_errno(ret); |
3830 | 3830 | ||
diff --git a/fs/ocfs2/refcounttree.h b/fs/ocfs2/refcounttree.h index 1e3446a655dd..2c238e682570 100644 --- a/fs/ocfs2/refcounttree.h +++ b/fs/ocfs2/refcounttree.h | |||
@@ -93,4 +93,10 @@ int ocfs2_add_refcount_flag(struct inode *inode, | |||
93 | int ocfs2_remove_refcount_tree(struct inode *inode, struct buffer_head *di_bh); | 93 | int ocfs2_remove_refcount_tree(struct inode *inode, struct buffer_head *di_bh); |
94 | int ocfs2_try_remove_refcount_tree(struct inode *inode, | 94 | int ocfs2_try_remove_refcount_tree(struct inode *inode, |
95 | struct buffer_head *di_bh); | 95 | struct buffer_head *di_bh); |
96 | int ocfs2_increase_refcount(handle_t *handle, | ||
97 | struct ocfs2_caching_info *ci, | ||
98 | struct buffer_head *ref_root_bh, | ||
99 | u64 cpos, u32 len, | ||
100 | struct ocfs2_alloc_context *meta_ac, | ||
101 | struct ocfs2_cached_dealloc_ctxt *dealloc); | ||
96 | #endif /* OCFS2_REFCOUNTTREE_H */ | 102 | #endif /* OCFS2_REFCOUNTTREE_H */ |
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index bb92a6d274c0..661ed9b85dbf 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c | |||
@@ -5877,6 +5877,929 @@ out: | |||
5877 | } | 5877 | } |
5878 | 5878 | ||
5879 | /* | 5879 | /* |
5880 | * Store the information we need in xattr reflink. | ||
5881 | * old_bh and new_bh are inode bh for the old and new inode. | ||
5882 | */ | ||
5883 | struct ocfs2_xattr_reflink { | ||
5884 | struct inode *old_inode; | ||
5885 | struct inode *new_inode; | ||
5886 | struct buffer_head *old_bh; | ||
5887 | struct buffer_head *new_bh; | ||
5888 | struct ocfs2_caching_info *ref_ci; | ||
5889 | struct buffer_head *ref_root_bh; | ||
5890 | struct ocfs2_cached_dealloc_ctxt *dealloc; | ||
5891 | }; | ||
5892 | |||
5893 | /* | ||
5894 | * Given a xattr header and xe offset, | ||
5895 | * return the proper xv and the corresponding bh. | ||
5896 | * xattr in inode, block and xattr tree have different implementaions. | ||
5897 | */ | ||
5898 | typedef int (get_xattr_value_root)(struct super_block *sb, | ||
5899 | struct buffer_head *bh, | ||
5900 | struct ocfs2_xattr_header *xh, | ||
5901 | int offset, | ||
5902 | struct ocfs2_xattr_value_root **xv, | ||
5903 | struct buffer_head **ret_bh, | ||
5904 | void *para); | ||
5905 | |||
5906 | /* | ||
5907 | * Calculate all the xattr value root metadata stored in this xattr header and | ||
5908 | * credits we need if we create them from the scratch. | ||
5909 | * We use get_xattr_value_root so that all types of xattr container can use it. | ||
5910 | */ | ||
5911 | static int ocfs2_value_metas_in_xattr_header(struct super_block *sb, | ||
5912 | struct buffer_head *bh, | ||
5913 | struct ocfs2_xattr_header *xh, | ||
5914 | int *metas, int *credits, | ||
5915 | int *num_recs, | ||
5916 | get_xattr_value_root *func, | ||
5917 | void *para) | ||
5918 | { | ||
5919 | int i, ret = 0; | ||
5920 | struct ocfs2_xattr_value_root *xv; | ||
5921 | struct ocfs2_xattr_entry *xe; | ||
5922 | |||
5923 | for (i = 0; i < le16_to_cpu(xh->xh_count); i++) { | ||
5924 | xe = &xh->xh_entries[i]; | ||
5925 | if (ocfs2_xattr_is_local(xe)) | ||
5926 | continue; | ||
5927 | |||
5928 | ret = func(sb, bh, xh, i, &xv, NULL, para); | ||
5929 | if (ret) { | ||
5930 | mlog_errno(ret); | ||
5931 | break; | ||
5932 | } | ||
5933 | |||
5934 | *metas += le16_to_cpu(xv->xr_list.l_tree_depth) * | ||
5935 | le16_to_cpu(xv->xr_list.l_next_free_rec); | ||
5936 | |||
5937 | *credits += ocfs2_calc_extend_credits(sb, | ||
5938 | &def_xv.xv.xr_list, | ||
5939 | le32_to_cpu(xv->xr_clusters)); | ||
5940 | |||
5941 | /* | ||
5942 | * If the value is a tree with depth > 1, We don't go deep | ||
5943 | * to the extent block, so just calculate a maximum record num. | ||
5944 | */ | ||
5945 | if (!xv->xr_list.l_tree_depth) | ||
5946 | *num_recs += xv->xr_list.l_next_free_rec; | ||
5947 | else | ||
5948 | *num_recs += ocfs2_clusters_for_bytes(sb, | ||
5949 | XATTR_SIZE_MAX); | ||
5950 | } | ||
5951 | |||
5952 | return ret; | ||
5953 | } | ||
5954 | |||
5955 | /* Used by xattr inode and block to return the right xv and buffer_head. */ | ||
5956 | static int ocfs2_get_xattr_value_root(struct super_block *sb, | ||
5957 | struct buffer_head *bh, | ||
5958 | struct ocfs2_xattr_header *xh, | ||
5959 | int offset, | ||
5960 | struct ocfs2_xattr_value_root **xv, | ||
5961 | struct buffer_head **ret_bh, | ||
5962 | void *para) | ||
5963 | { | ||
5964 | struct ocfs2_xattr_entry *xe = &xh->xh_entries[offset]; | ||
5965 | |||
5966 | *xv = (struct ocfs2_xattr_value_root *)((void *)xh + | ||
5967 | le16_to_cpu(xe->xe_name_offset) + | ||
5968 | OCFS2_XATTR_SIZE(xe->xe_name_len)); | ||
5969 | |||
5970 | if (ret_bh) | ||
5971 | *ret_bh = bh; | ||
5972 | |||
5973 | return 0; | ||
5974 | } | ||
5975 | |||
5976 | /* | ||
5977 | * Lock the meta_ac and caculate how much credits we need for reflink xattrs. | ||
5978 | * It is only used for inline xattr and xattr block. | ||
5979 | */ | ||
5980 | static int ocfs2_reflink_lock_xattr_allocators(struct ocfs2_super *osb, | ||
5981 | struct ocfs2_xattr_header *xh, | ||
5982 | struct buffer_head *ref_root_bh, | ||
5983 | int *credits, | ||
5984 | struct ocfs2_alloc_context **meta_ac) | ||
5985 | { | ||
5986 | int ret, meta_add = 0, num_recs = 0; | ||
5987 | struct ocfs2_refcount_block *rb = | ||
5988 | (struct ocfs2_refcount_block *)ref_root_bh->b_data; | ||
5989 | |||
5990 | *credits = 0; | ||
5991 | |||
5992 | ret = ocfs2_value_metas_in_xattr_header(osb->sb, NULL, xh, | ||
5993 | &meta_add, credits, &num_recs, | ||
5994 | ocfs2_get_xattr_value_root, | ||
5995 | NULL); | ||
5996 | if (ret) { | ||
5997 | mlog_errno(ret); | ||
5998 | goto out; | ||
5999 | } | ||
6000 | |||
6001 | /* | ||
6002 | * We need to add/modify num_recs in refcount tree, so just calculate | ||
6003 | * an approximate number we need for refcount tree change. | ||
6004 | * Sometimes we need to split the tree, and after split, half recs | ||
6005 | * will be moved to the new block, and a new block can only provide | ||
6006 | * half number of recs. So we multiple new blocks by 2. | ||
6007 | */ | ||
6008 | num_recs = num_recs / ocfs2_refcount_recs_per_rb(osb->sb) * 2; | ||
6009 | meta_add += num_recs; | ||
6010 | *credits += num_recs + num_recs * OCFS2_EXPAND_REFCOUNT_TREE_CREDITS; | ||
6011 | if (le32_to_cpu(rb->rf_flags) & OCFS2_REFCOUNT_TREE_FL) | ||
6012 | *credits += le16_to_cpu(rb->rf_list.l_tree_depth) * | ||
6013 | le16_to_cpu(rb->rf_list.l_next_free_rec) + 1; | ||
6014 | else | ||
6015 | *credits += 1; | ||
6016 | |||
6017 | ret = ocfs2_reserve_new_metadata_blocks(osb, meta_add, meta_ac); | ||
6018 | if (ret) | ||
6019 | mlog_errno(ret); | ||
6020 | |||
6021 | out: | ||
6022 | return ret; | ||
6023 | } | ||
6024 | |||
6025 | /* | ||
6026 | * Given a xattr header, reflink all the xattrs in this container. | ||
6027 | * It can be used for inode, block and bucket. | ||
6028 | * | ||
6029 | * NOTE: | ||
6030 | * Before we call this function, the caller has memcpy the xattr in | ||
6031 | * old_xh to the new_xh. | ||
6032 | */ | ||
6033 | static int ocfs2_reflink_xattr_header(handle_t *handle, | ||
6034 | struct ocfs2_xattr_reflink *args, | ||
6035 | struct buffer_head *old_bh, | ||
6036 | struct ocfs2_xattr_header *xh, | ||
6037 | struct buffer_head *new_bh, | ||
6038 | struct ocfs2_xattr_header *new_xh, | ||
6039 | struct ocfs2_xattr_value_buf *vb, | ||
6040 | struct ocfs2_alloc_context *meta_ac, | ||
6041 | get_xattr_value_root *func, | ||
6042 | void *para) | ||
6043 | { | ||
6044 | int ret = 0, i; | ||
6045 | struct super_block *sb = args->old_inode->i_sb; | ||
6046 | struct buffer_head *value_bh; | ||
6047 | struct ocfs2_xattr_entry *xe; | ||
6048 | struct ocfs2_xattr_value_root *xv, *new_xv; | ||
6049 | struct ocfs2_extent_tree data_et; | ||
6050 | u32 clusters, cpos, p_cluster, num_clusters; | ||
6051 | unsigned int ext_flags = 0; | ||
6052 | |||
6053 | mlog(0, "reflink xattr in container %llu, count = %u\n", | ||
6054 | (unsigned long long)old_bh->b_blocknr, le16_to_cpu(xh->xh_count)); | ||
6055 | for (i = 0; i < le16_to_cpu(xh->xh_count); i++) { | ||
6056 | xe = &xh->xh_entries[i]; | ||
6057 | |||
6058 | if (ocfs2_xattr_is_local(xe)) | ||
6059 | continue; | ||
6060 | |||
6061 | ret = func(sb, old_bh, xh, i, &xv, NULL, para); | ||
6062 | if (ret) { | ||
6063 | mlog_errno(ret); | ||
6064 | break; | ||
6065 | } | ||
6066 | |||
6067 | ret = func(sb, new_bh, new_xh, i, &new_xv, &value_bh, para); | ||
6068 | if (ret) { | ||
6069 | mlog_errno(ret); | ||
6070 | break; | ||
6071 | } | ||
6072 | |||
6073 | /* | ||
6074 | * For the xattr which has l_tree_depth = 0, all the extent | ||
6075 | * recs have already be copied to the new xh with the | ||
6076 | * propriate OCFS2_EXT_REFCOUNTED flag we just need to | ||
6077 | * increase the refount count int the refcount tree. | ||
6078 | * | ||
6079 | * For the xattr which has l_tree_depth > 0, we need | ||
6080 | * to initialize it to the empty default value root, | ||
6081 | * and then insert the extents one by one. | ||
6082 | */ | ||
6083 | if (xv->xr_list.l_tree_depth) { | ||
6084 | memcpy(new_xv, &def_xv, sizeof(def_xv)); | ||
6085 | vb->vb_xv = new_xv; | ||
6086 | vb->vb_bh = value_bh; | ||
6087 | ocfs2_init_xattr_value_extent_tree(&data_et, | ||
6088 | INODE_CACHE(args->new_inode), vb); | ||
6089 | } | ||
6090 | |||
6091 | clusters = le32_to_cpu(xv->xr_clusters); | ||
6092 | cpos = 0; | ||
6093 | while (cpos < clusters) { | ||
6094 | ret = ocfs2_xattr_get_clusters(args->old_inode, | ||
6095 | cpos, | ||
6096 | &p_cluster, | ||
6097 | &num_clusters, | ||
6098 | &xv->xr_list, | ||
6099 | &ext_flags); | ||
6100 | if (ret) { | ||
6101 | mlog_errno(ret); | ||
6102 | goto out; | ||
6103 | } | ||
6104 | |||
6105 | BUG_ON(!p_cluster); | ||
6106 | |||
6107 | if (xv->xr_list.l_tree_depth) { | ||
6108 | ret = ocfs2_insert_extent(handle, | ||
6109 | &data_et, cpos, | ||
6110 | ocfs2_clusters_to_blocks( | ||
6111 | args->old_inode->i_sb, | ||
6112 | p_cluster), | ||
6113 | num_clusters, ext_flags, | ||
6114 | meta_ac); | ||
6115 | if (ret) { | ||
6116 | mlog_errno(ret); | ||
6117 | goto out; | ||
6118 | } | ||
6119 | } | ||
6120 | |||
6121 | ret = ocfs2_increase_refcount(handle, args->ref_ci, | ||
6122 | args->ref_root_bh, | ||
6123 | p_cluster, num_clusters, | ||
6124 | meta_ac, args->dealloc); | ||
6125 | if (ret) { | ||
6126 | mlog_errno(ret); | ||
6127 | goto out; | ||
6128 | } | ||
6129 | |||
6130 | cpos += num_clusters; | ||
6131 | } | ||
6132 | } | ||
6133 | |||
6134 | out: | ||
6135 | return ret; | ||
6136 | } | ||
6137 | |||
6138 | static int ocfs2_reflink_xattr_inline(struct ocfs2_xattr_reflink *args) | ||
6139 | { | ||
6140 | int ret = 0, credits = 0; | ||
6141 | handle_t *handle; | ||
6142 | struct ocfs2_super *osb = OCFS2_SB(args->old_inode->i_sb); | ||
6143 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)args->old_bh->b_data; | ||
6144 | int inline_size = le16_to_cpu(di->i_xattr_inline_size); | ||
6145 | int header_off = osb->sb->s_blocksize - inline_size; | ||
6146 | struct ocfs2_xattr_header *xh = (struct ocfs2_xattr_header *) | ||
6147 | (args->old_bh->b_data + header_off); | ||
6148 | struct ocfs2_xattr_header *new_xh = (struct ocfs2_xattr_header *) | ||
6149 | (args->new_bh->b_data + header_off); | ||
6150 | struct ocfs2_alloc_context *meta_ac = NULL; | ||
6151 | struct ocfs2_inode_info *new_oi; | ||
6152 | struct ocfs2_dinode *new_di; | ||
6153 | struct ocfs2_xattr_value_buf vb = { | ||
6154 | .vb_bh = args->new_bh, | ||
6155 | .vb_access = ocfs2_journal_access_di, | ||
6156 | }; | ||
6157 | |||
6158 | ret = ocfs2_reflink_lock_xattr_allocators(osb, xh, args->ref_root_bh, | ||
6159 | &credits, &meta_ac); | ||
6160 | if (ret) { | ||
6161 | mlog_errno(ret); | ||
6162 | goto out; | ||
6163 | } | ||
6164 | |||
6165 | handle = ocfs2_start_trans(osb, credits); | ||
6166 | if (IS_ERR(handle)) { | ||
6167 | ret = PTR_ERR(handle); | ||
6168 | mlog_errno(ret); | ||
6169 | goto out; | ||
6170 | } | ||
6171 | |||
6172 | ret = ocfs2_journal_access_di(handle, INODE_CACHE(args->new_inode), | ||
6173 | args->new_bh, OCFS2_JOURNAL_ACCESS_WRITE); | ||
6174 | if (ret) { | ||
6175 | mlog_errno(ret); | ||
6176 | goto out_commit; | ||
6177 | } | ||
6178 | |||
6179 | memcpy(args->new_bh->b_data + header_off, | ||
6180 | args->old_bh->b_data + header_off, inline_size); | ||
6181 | |||
6182 | new_di = (struct ocfs2_dinode *)args->new_bh->b_data; | ||
6183 | new_di->i_xattr_inline_size = cpu_to_le16(inline_size); | ||
6184 | |||
6185 | ret = ocfs2_reflink_xattr_header(handle, args, args->old_bh, xh, | ||
6186 | args->new_bh, new_xh, &vb, meta_ac, | ||
6187 | ocfs2_get_xattr_value_root, NULL); | ||
6188 | if (ret) { | ||
6189 | mlog_errno(ret); | ||
6190 | goto out_commit; | ||
6191 | } | ||
6192 | |||
6193 | new_oi = OCFS2_I(args->new_inode); | ||
6194 | spin_lock(&new_oi->ip_lock); | ||
6195 | new_oi->ip_dyn_features |= OCFS2_HAS_XATTR_FL | OCFS2_INLINE_XATTR_FL; | ||
6196 | new_di->i_dyn_features = cpu_to_le16(new_oi->ip_dyn_features); | ||
6197 | spin_unlock(&new_oi->ip_lock); | ||
6198 | |||
6199 | ocfs2_journal_dirty(handle, args->new_bh); | ||
6200 | |||
6201 | out_commit: | ||
6202 | ocfs2_commit_trans(osb, handle); | ||
6203 | |||
6204 | out: | ||
6205 | if (meta_ac) | ||
6206 | ocfs2_free_alloc_context(meta_ac); | ||
6207 | return ret; | ||
6208 | } | ||
6209 | |||
6210 | static int ocfs2_create_empty_xattr_block(struct inode *inode, | ||
6211 | struct buffer_head *fe_bh, | ||
6212 | struct buffer_head **ret_bh, | ||
6213 | int indexed) | ||
6214 | { | ||
6215 | int ret; | ||
6216 | handle_t *handle; | ||
6217 | struct ocfs2_alloc_context *meta_ac; | ||
6218 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
6219 | |||
6220 | ret = ocfs2_reserve_new_metadata_blocks(osb, 1, &meta_ac); | ||
6221 | if (ret < 0) { | ||
6222 | mlog_errno(ret); | ||
6223 | return ret; | ||
6224 | } | ||
6225 | |||
6226 | handle = ocfs2_start_trans(osb, OCFS2_XATTR_BLOCK_CREATE_CREDITS); | ||
6227 | if (IS_ERR(handle)) { | ||
6228 | ret = PTR_ERR(handle); | ||
6229 | mlog_errno(ret); | ||
6230 | goto out; | ||
6231 | } | ||
6232 | |||
6233 | mlog(0, "create new xattr block for inode %llu, index = %d\n", | ||
6234 | (unsigned long long)fe_bh->b_blocknr, indexed); | ||
6235 | ret = ocfs2_create_xattr_block(handle, inode, fe_bh, | ||
6236 | meta_ac, ret_bh, indexed); | ||
6237 | if (ret) | ||
6238 | mlog_errno(ret); | ||
6239 | |||
6240 | ocfs2_commit_trans(osb, handle); | ||
6241 | out: | ||
6242 | ocfs2_free_alloc_context(meta_ac); | ||
6243 | return ret; | ||
6244 | } | ||
6245 | |||
6246 | static int ocfs2_reflink_xattr_block(struct ocfs2_xattr_reflink *args, | ||
6247 | struct buffer_head *blk_bh, | ||
6248 | struct buffer_head *new_blk_bh) | ||
6249 | { | ||
6250 | int ret = 0, credits = 0; | ||
6251 | handle_t *handle; | ||
6252 | struct ocfs2_inode_info *new_oi = OCFS2_I(args->new_inode); | ||
6253 | struct ocfs2_dinode *new_di; | ||
6254 | struct ocfs2_super *osb = OCFS2_SB(args->new_inode->i_sb); | ||
6255 | int header_off = offsetof(struct ocfs2_xattr_block, xb_attrs.xb_header); | ||
6256 | struct ocfs2_xattr_block *xb = | ||
6257 | (struct ocfs2_xattr_block *)blk_bh->b_data; | ||
6258 | struct ocfs2_xattr_header *xh = &xb->xb_attrs.xb_header; | ||
6259 | struct ocfs2_xattr_block *new_xb = | ||
6260 | (struct ocfs2_xattr_block *)new_blk_bh->b_data; | ||
6261 | struct ocfs2_xattr_header *new_xh = &new_xb->xb_attrs.xb_header; | ||
6262 | struct ocfs2_alloc_context *meta_ac; | ||
6263 | struct ocfs2_xattr_value_buf vb = { | ||
6264 | .vb_bh = new_blk_bh, | ||
6265 | .vb_access = ocfs2_journal_access_xb, | ||
6266 | }; | ||
6267 | |||
6268 | ret = ocfs2_reflink_lock_xattr_allocators(osb, xh, args->ref_root_bh, | ||
6269 | &credits, &meta_ac); | ||
6270 | if (ret) { | ||
6271 | mlog_errno(ret); | ||
6272 | return ret; | ||
6273 | } | ||
6274 | |||
6275 | /* One more credits in case we need to add xattr flags in new inode. */ | ||
6276 | handle = ocfs2_start_trans(osb, credits + 1); | ||
6277 | if (IS_ERR(handle)) { | ||
6278 | ret = PTR_ERR(handle); | ||
6279 | mlog_errno(ret); | ||
6280 | goto out; | ||
6281 | } | ||
6282 | |||
6283 | if (!(new_oi->ip_dyn_features & OCFS2_HAS_XATTR_FL)) { | ||
6284 | ret = ocfs2_journal_access_di(handle, | ||
6285 | INODE_CACHE(args->new_inode), | ||
6286 | args->new_bh, | ||
6287 | OCFS2_JOURNAL_ACCESS_WRITE); | ||
6288 | if (ret) { | ||
6289 | mlog_errno(ret); | ||
6290 | goto out_commit; | ||
6291 | } | ||
6292 | } | ||
6293 | |||
6294 | ret = ocfs2_journal_access_xb(handle, INODE_CACHE(args->new_inode), | ||
6295 | new_blk_bh, OCFS2_JOURNAL_ACCESS_WRITE); | ||
6296 | if (ret) { | ||
6297 | mlog_errno(ret); | ||
6298 | goto out_commit; | ||
6299 | } | ||
6300 | |||
6301 | memcpy(new_blk_bh->b_data + header_off, blk_bh->b_data + header_off, | ||
6302 | osb->sb->s_blocksize - header_off); | ||
6303 | |||
6304 | ret = ocfs2_reflink_xattr_header(handle, args, blk_bh, xh, | ||
6305 | new_blk_bh, new_xh, &vb, meta_ac, | ||
6306 | ocfs2_get_xattr_value_root, NULL); | ||
6307 | if (ret) { | ||
6308 | mlog_errno(ret); | ||
6309 | goto out_commit; | ||
6310 | } | ||
6311 | |||
6312 | ocfs2_journal_dirty(handle, new_blk_bh); | ||
6313 | |||
6314 | if (!(new_oi->ip_dyn_features & OCFS2_HAS_XATTR_FL)) { | ||
6315 | new_di = (struct ocfs2_dinode *)args->new_bh->b_data; | ||
6316 | spin_lock(&new_oi->ip_lock); | ||
6317 | new_oi->ip_dyn_features |= OCFS2_HAS_XATTR_FL; | ||
6318 | new_di->i_dyn_features = cpu_to_le16(new_oi->ip_dyn_features); | ||
6319 | spin_unlock(&new_oi->ip_lock); | ||
6320 | |||
6321 | ocfs2_journal_dirty(handle, args->new_bh); | ||
6322 | } | ||
6323 | |||
6324 | out_commit: | ||
6325 | ocfs2_commit_trans(osb, handle); | ||
6326 | |||
6327 | out: | ||
6328 | ocfs2_free_alloc_context(meta_ac); | ||
6329 | return ret; | ||
6330 | } | ||
6331 | |||
6332 | struct ocfs2_reflink_xattr_tree_args { | ||
6333 | struct ocfs2_xattr_reflink *reflink; | ||
6334 | struct buffer_head *old_blk_bh; | ||
6335 | struct buffer_head *new_blk_bh; | ||
6336 | struct ocfs2_xattr_bucket *old_bucket; | ||
6337 | struct ocfs2_xattr_bucket *new_bucket; | ||
6338 | }; | ||
6339 | |||
6340 | /* | ||
6341 | * NOTE: | ||
6342 | * We have to handle the case that both old bucket and new bucket | ||
6343 | * will call this function to get the right ret_bh. | ||
6344 | * So The caller must give us the right bh. | ||
6345 | */ | ||
6346 | static int ocfs2_get_reflink_xattr_value_root(struct super_block *sb, | ||
6347 | struct buffer_head *bh, | ||
6348 | struct ocfs2_xattr_header *xh, | ||
6349 | int offset, | ||
6350 | struct ocfs2_xattr_value_root **xv, | ||
6351 | struct buffer_head **ret_bh, | ||
6352 | void *para) | ||
6353 | { | ||
6354 | struct ocfs2_reflink_xattr_tree_args *args = | ||
6355 | (struct ocfs2_reflink_xattr_tree_args *)para; | ||
6356 | struct ocfs2_xattr_bucket *bucket; | ||
6357 | |||
6358 | if (bh == args->old_bucket->bu_bhs[0]) | ||
6359 | bucket = args->old_bucket; | ||
6360 | else | ||
6361 | bucket = args->new_bucket; | ||
6362 | |||
6363 | return ocfs2_get_xattr_tree_value_root(sb, bucket, offset, | ||
6364 | xv, ret_bh); | ||
6365 | } | ||
6366 | |||
6367 | struct ocfs2_value_tree_metas { | ||
6368 | int num_metas; | ||
6369 | int credits; | ||
6370 | int num_recs; | ||
6371 | }; | ||
6372 | |||
6373 | static int ocfs2_value_tree_metas_in_bucket(struct super_block *sb, | ||
6374 | struct buffer_head *bh, | ||
6375 | struct ocfs2_xattr_header *xh, | ||
6376 | int offset, | ||
6377 | struct ocfs2_xattr_value_root **xv, | ||
6378 | struct buffer_head **ret_bh, | ||
6379 | void *para) | ||
6380 | { | ||
6381 | struct ocfs2_xattr_bucket *bucket = | ||
6382 | (struct ocfs2_xattr_bucket *)para; | ||
6383 | |||
6384 | return ocfs2_get_xattr_tree_value_root(sb, bucket, offset, | ||
6385 | xv, ret_bh); | ||
6386 | } | ||
6387 | |||
6388 | static int ocfs2_calc_value_tree_metas(struct inode *inode, | ||
6389 | struct ocfs2_xattr_bucket *bucket, | ||
6390 | void *para) | ||
6391 | { | ||
6392 | struct ocfs2_value_tree_metas *metas = | ||
6393 | (struct ocfs2_value_tree_metas *)para; | ||
6394 | struct ocfs2_xattr_header *xh = | ||
6395 | (struct ocfs2_xattr_header *)bucket->bu_bhs[0]->b_data; | ||
6396 | |||
6397 | /* Add the credits for this bucket first. */ | ||
6398 | metas->credits += bucket->bu_blocks; | ||
6399 | return ocfs2_value_metas_in_xattr_header(inode->i_sb, bucket->bu_bhs[0], | ||
6400 | xh, &metas->num_metas, | ||
6401 | &metas->credits, &metas->num_recs, | ||
6402 | ocfs2_value_tree_metas_in_bucket, | ||
6403 | bucket); | ||
6404 | } | ||
6405 | |||
6406 | /* | ||
6407 | * Given a xattr extent rec starting from blkno and having len clusters, | ||
6408 | * iterate all the buckets calculate how much metadata we need for reflinking | ||
6409 | * all the ocfs2_xattr_value_root and lock the allocators accordingly. | ||
6410 | */ | ||
6411 | static int ocfs2_lock_reflink_xattr_rec_allocators( | ||
6412 | struct ocfs2_reflink_xattr_tree_args *args, | ||
6413 | struct ocfs2_extent_tree *xt_et, | ||
6414 | u64 blkno, u32 len, int *credits, | ||
6415 | struct ocfs2_alloc_context **meta_ac, | ||
6416 | struct ocfs2_alloc_context **data_ac) | ||
6417 | { | ||
6418 | int ret, num_free_extents; | ||
6419 | struct ocfs2_value_tree_metas metas; | ||
6420 | struct ocfs2_super *osb = OCFS2_SB(args->reflink->old_inode->i_sb); | ||
6421 | struct ocfs2_refcount_block *rb; | ||
6422 | |||
6423 | memset(&metas, 0, sizeof(metas)); | ||
6424 | |||
6425 | ret = ocfs2_iterate_xattr_buckets(args->reflink->old_inode, blkno, len, | ||
6426 | ocfs2_calc_value_tree_metas, &metas); | ||
6427 | if (ret) { | ||
6428 | mlog_errno(ret); | ||
6429 | goto out; | ||
6430 | } | ||
6431 | |||
6432 | *credits = metas.credits; | ||
6433 | |||
6434 | /* | ||
6435 | * Calculate we need for refcount tree change. | ||
6436 | * | ||
6437 | * We need to add/modify num_recs in refcount tree, so just calculate | ||
6438 | * an approximate number we need for refcount tree change. | ||
6439 | * Sometimes we need to split the tree, and after split, half recs | ||
6440 | * will be moved to the new block, and a new block can only provide | ||
6441 | * half number of recs. So we multiple new blocks by 2. | ||
6442 | * In the end, we have to add credits for modifying the already | ||
6443 | * existed refcount block. | ||
6444 | */ | ||
6445 | rb = (struct ocfs2_refcount_block *)args->reflink->ref_root_bh->b_data; | ||
6446 | metas.num_recs = | ||
6447 | (metas.num_recs + ocfs2_refcount_recs_per_rb(osb->sb) - 1) / | ||
6448 | ocfs2_refcount_recs_per_rb(osb->sb) * 2; | ||
6449 | metas.num_metas += metas.num_recs; | ||
6450 | *credits += metas.num_recs + | ||
6451 | metas.num_recs * OCFS2_EXPAND_REFCOUNT_TREE_CREDITS; | ||
6452 | if (le32_to_cpu(rb->rf_flags) & OCFS2_REFCOUNT_TREE_FL) | ||
6453 | *credits += le16_to_cpu(rb->rf_list.l_tree_depth) * | ||
6454 | le16_to_cpu(rb->rf_list.l_next_free_rec) + 1; | ||
6455 | else | ||
6456 | *credits += 1; | ||
6457 | |||
6458 | /* count in the xattr tree change. */ | ||
6459 | num_free_extents = ocfs2_num_free_extents(osb, xt_et); | ||
6460 | if (num_free_extents < 0) { | ||
6461 | ret = num_free_extents; | ||
6462 | mlog_errno(ret); | ||
6463 | goto out; | ||
6464 | } | ||
6465 | |||
6466 | if (num_free_extents < len) | ||
6467 | metas.num_metas += ocfs2_extend_meta_needed(xt_et->et_root_el); | ||
6468 | |||
6469 | *credits += ocfs2_calc_extend_credits(osb->sb, | ||
6470 | xt_et->et_root_el, len); | ||
6471 | |||
6472 | if (metas.num_metas) { | ||
6473 | ret = ocfs2_reserve_new_metadata_blocks(osb, metas.num_metas, | ||
6474 | meta_ac); | ||
6475 | if (ret) { | ||
6476 | mlog_errno(ret); | ||
6477 | goto out; | ||
6478 | } | ||
6479 | } | ||
6480 | |||
6481 | if (len) { | ||
6482 | ret = ocfs2_reserve_clusters(osb, len, data_ac); | ||
6483 | if (ret) | ||
6484 | mlog_errno(ret); | ||
6485 | } | ||
6486 | out: | ||
6487 | if (ret) { | ||
6488 | if (*meta_ac) { | ||
6489 | ocfs2_free_alloc_context(*meta_ac); | ||
6490 | meta_ac = NULL; | ||
6491 | } | ||
6492 | } | ||
6493 | |||
6494 | return ret; | ||
6495 | } | ||
6496 | |||
6497 | static int ocfs2_reflink_xattr_buckets(handle_t *handle, | ||
6498 | u64 blkno, u64 new_blkno, u32 clusters, | ||
6499 | struct ocfs2_alloc_context *meta_ac, | ||
6500 | struct ocfs2_alloc_context *data_ac, | ||
6501 | struct ocfs2_reflink_xattr_tree_args *args) | ||
6502 | { | ||
6503 | int i, j, ret = 0; | ||
6504 | struct super_block *sb = args->reflink->old_inode->i_sb; | ||
6505 | u32 bpc = ocfs2_xattr_buckets_per_cluster(OCFS2_SB(sb)); | ||
6506 | u32 num_buckets = clusters * bpc; | ||
6507 | int bpb = args->old_bucket->bu_blocks; | ||
6508 | struct ocfs2_xattr_value_buf vb = { | ||
6509 | .vb_access = ocfs2_journal_access, | ||
6510 | }; | ||
6511 | |||
6512 | for (i = 0; i < num_buckets; i++, blkno += bpb, new_blkno += bpb) { | ||
6513 | ret = ocfs2_read_xattr_bucket(args->old_bucket, blkno); | ||
6514 | if (ret) { | ||
6515 | mlog_errno(ret); | ||
6516 | break; | ||
6517 | } | ||
6518 | |||
6519 | ret = ocfs2_init_xattr_bucket(args->new_bucket, new_blkno); | ||
6520 | if (ret) { | ||
6521 | mlog_errno(ret); | ||
6522 | break; | ||
6523 | } | ||
6524 | |||
6525 | /* | ||
6526 | * The real bucket num in this series of blocks is stored | ||
6527 | * in the 1st bucket. | ||
6528 | */ | ||
6529 | if (i == 0) | ||
6530 | num_buckets = le16_to_cpu( | ||
6531 | bucket_xh(args->old_bucket)->xh_num_buckets); | ||
6532 | |||
6533 | ret = ocfs2_xattr_bucket_journal_access(handle, | ||
6534 | args->new_bucket, | ||
6535 | OCFS2_JOURNAL_ACCESS_CREATE); | ||
6536 | if (ret) { | ||
6537 | mlog_errno(ret); | ||
6538 | break; | ||
6539 | } | ||
6540 | |||
6541 | for (j = 0; j < bpb; j++) | ||
6542 | memcpy(bucket_block(args->new_bucket, j), | ||
6543 | bucket_block(args->old_bucket, j), | ||
6544 | sb->s_blocksize); | ||
6545 | |||
6546 | ocfs2_xattr_bucket_journal_dirty(handle, args->new_bucket); | ||
6547 | |||
6548 | ret = ocfs2_reflink_xattr_header(handle, args->reflink, | ||
6549 | args->old_bucket->bu_bhs[0], | ||
6550 | bucket_xh(args->old_bucket), | ||
6551 | args->new_bucket->bu_bhs[0], | ||
6552 | bucket_xh(args->new_bucket), | ||
6553 | &vb, meta_ac, | ||
6554 | ocfs2_get_reflink_xattr_value_root, | ||
6555 | args); | ||
6556 | if (ret) { | ||
6557 | mlog_errno(ret); | ||
6558 | break; | ||
6559 | } | ||
6560 | |||
6561 | /* | ||
6562 | * Re-access and dirty the bucket to calculate metaecc. | ||
6563 | * Because we may extend the transaction in reflink_xattr_header | ||
6564 | * which will let the already accessed block gone. | ||
6565 | */ | ||
6566 | ret = ocfs2_xattr_bucket_journal_access(handle, | ||
6567 | args->new_bucket, | ||
6568 | OCFS2_JOURNAL_ACCESS_WRITE); | ||
6569 | if (ret) { | ||
6570 | mlog_errno(ret); | ||
6571 | break; | ||
6572 | } | ||
6573 | |||
6574 | ocfs2_xattr_bucket_journal_dirty(handle, args->new_bucket); | ||
6575 | ocfs2_xattr_bucket_relse(args->old_bucket); | ||
6576 | ocfs2_xattr_bucket_relse(args->new_bucket); | ||
6577 | } | ||
6578 | |||
6579 | ocfs2_xattr_bucket_relse(args->old_bucket); | ||
6580 | ocfs2_xattr_bucket_relse(args->new_bucket); | ||
6581 | return ret; | ||
6582 | } | ||
6583 | /* | ||
6584 | * Create the same xattr extent record in the new inode's xattr tree. | ||
6585 | */ | ||
6586 | static int ocfs2_reflink_xattr_rec(struct inode *inode, | ||
6587 | struct buffer_head *root_bh, | ||
6588 | u64 blkno, | ||
6589 | u32 cpos, | ||
6590 | u32 len, | ||
6591 | void *para) | ||
6592 | { | ||
6593 | int ret, credits = 0; | ||
6594 | u32 p_cluster, num_clusters; | ||
6595 | u64 new_blkno; | ||
6596 | handle_t *handle; | ||
6597 | struct ocfs2_reflink_xattr_tree_args *args = | ||
6598 | (struct ocfs2_reflink_xattr_tree_args *)para; | ||
6599 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
6600 | struct ocfs2_alloc_context *meta_ac = NULL; | ||
6601 | struct ocfs2_alloc_context *data_ac = NULL; | ||
6602 | struct ocfs2_extent_tree et; | ||
6603 | |||
6604 | ocfs2_init_xattr_tree_extent_tree(&et, | ||
6605 | INODE_CACHE(args->reflink->new_inode), | ||
6606 | args->new_blk_bh); | ||
6607 | |||
6608 | ret = ocfs2_lock_reflink_xattr_rec_allocators(args, &et, blkno, | ||
6609 | len, &credits, | ||
6610 | &meta_ac, &data_ac); | ||
6611 | if (ret) { | ||
6612 | mlog_errno(ret); | ||
6613 | goto out; | ||
6614 | } | ||
6615 | |||
6616 | handle = ocfs2_start_trans(osb, credits); | ||
6617 | if (IS_ERR(handle)) { | ||
6618 | ret = PTR_ERR(handle); | ||
6619 | mlog_errno(ret); | ||
6620 | goto out; | ||
6621 | } | ||
6622 | |||
6623 | ret = ocfs2_claim_clusters(osb, handle, data_ac, | ||
6624 | len, &p_cluster, &num_clusters); | ||
6625 | if (ret) { | ||
6626 | mlog_errno(ret); | ||
6627 | goto out_commit; | ||
6628 | } | ||
6629 | |||
6630 | new_blkno = ocfs2_clusters_to_blocks(osb->sb, p_cluster); | ||
6631 | |||
6632 | mlog(0, "reflink xattr buckets %llu to %llu, len %u\n", | ||
6633 | (unsigned long long)blkno, (unsigned long long)new_blkno, len); | ||
6634 | ret = ocfs2_reflink_xattr_buckets(handle, blkno, new_blkno, len, | ||
6635 | meta_ac, data_ac, args); | ||
6636 | if (ret) { | ||
6637 | mlog_errno(ret); | ||
6638 | goto out_commit; | ||
6639 | } | ||
6640 | |||
6641 | mlog(0, "insert new xattr extent rec start %llu len %u to %u\n", | ||
6642 | (unsigned long long)new_blkno, len, cpos); | ||
6643 | ret = ocfs2_insert_extent(handle, &et, cpos, new_blkno, | ||
6644 | len, 0, meta_ac); | ||
6645 | if (ret) | ||
6646 | mlog_errno(ret); | ||
6647 | |||
6648 | out_commit: | ||
6649 | ocfs2_commit_trans(osb, handle); | ||
6650 | |||
6651 | out: | ||
6652 | if (meta_ac) | ||
6653 | ocfs2_free_alloc_context(meta_ac); | ||
6654 | if (data_ac) | ||
6655 | ocfs2_free_alloc_context(data_ac); | ||
6656 | return ret; | ||
6657 | } | ||
6658 | |||
6659 | /* | ||
6660 | * Create reflinked xattr buckets. | ||
6661 | * We will add bucket one by one, and refcount all the xattrs in the bucket | ||
6662 | * if they are stored outside. | ||
6663 | */ | ||
6664 | static int ocfs2_reflink_xattr_tree(struct ocfs2_xattr_reflink *args, | ||
6665 | struct buffer_head *blk_bh, | ||
6666 | struct buffer_head *new_blk_bh) | ||
6667 | { | ||
6668 | int ret; | ||
6669 | struct ocfs2_reflink_xattr_tree_args para; | ||
6670 | |||
6671 | memset(¶, 0, sizeof(para)); | ||
6672 | para.reflink = args; | ||
6673 | para.old_blk_bh = blk_bh; | ||
6674 | para.new_blk_bh = new_blk_bh; | ||
6675 | |||
6676 | para.old_bucket = ocfs2_xattr_bucket_new(args->old_inode); | ||
6677 | if (!para.old_bucket) { | ||
6678 | mlog_errno(-ENOMEM); | ||
6679 | return -ENOMEM; | ||
6680 | } | ||
6681 | |||
6682 | para.new_bucket = ocfs2_xattr_bucket_new(args->new_inode); | ||
6683 | if (!para.new_bucket) { | ||
6684 | ret = -ENOMEM; | ||
6685 | mlog_errno(ret); | ||
6686 | goto out; | ||
6687 | } | ||
6688 | |||
6689 | ret = ocfs2_iterate_xattr_index_block(args->old_inode, blk_bh, | ||
6690 | ocfs2_reflink_xattr_rec, | ||
6691 | ¶); | ||
6692 | if (ret) | ||
6693 | mlog_errno(ret); | ||
6694 | |||
6695 | out: | ||
6696 | ocfs2_xattr_bucket_free(para.old_bucket); | ||
6697 | ocfs2_xattr_bucket_free(para.new_bucket); | ||
6698 | return ret; | ||
6699 | } | ||
6700 | |||
6701 | static int ocfs2_reflink_xattr_in_block(struct ocfs2_xattr_reflink *args, | ||
6702 | struct buffer_head *blk_bh) | ||
6703 | { | ||
6704 | int ret, indexed = 0; | ||
6705 | struct buffer_head *new_blk_bh = NULL; | ||
6706 | struct ocfs2_xattr_block *xb = | ||
6707 | (struct ocfs2_xattr_block *)blk_bh->b_data; | ||
6708 | |||
6709 | |||
6710 | if (le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED) | ||
6711 | indexed = 1; | ||
6712 | |||
6713 | ret = ocfs2_create_empty_xattr_block(args->new_inode, args->new_bh, | ||
6714 | &new_blk_bh, indexed); | ||
6715 | if (ret) { | ||
6716 | mlog_errno(ret); | ||
6717 | goto out; | ||
6718 | } | ||
6719 | |||
6720 | if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) | ||
6721 | ret = ocfs2_reflink_xattr_block(args, blk_bh, new_blk_bh); | ||
6722 | else | ||
6723 | ret = ocfs2_reflink_xattr_tree(args, blk_bh, new_blk_bh); | ||
6724 | if (ret) | ||
6725 | mlog_errno(ret); | ||
6726 | |||
6727 | out: | ||
6728 | brelse(new_blk_bh); | ||
6729 | return ret; | ||
6730 | } | ||
6731 | |||
6732 | int ocfs2_reflink_xattrs(struct inode *old_inode, | ||
6733 | struct buffer_head *old_bh, | ||
6734 | struct inode *new_inode, | ||
6735 | struct buffer_head *new_bh) | ||
6736 | { | ||
6737 | int ret; | ||
6738 | struct ocfs2_xattr_reflink args; | ||
6739 | struct ocfs2_inode_info *oi = OCFS2_I(old_inode); | ||
6740 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)old_bh->b_data; | ||
6741 | struct buffer_head *blk_bh = NULL; | ||
6742 | struct ocfs2_cached_dealloc_ctxt dealloc; | ||
6743 | struct ocfs2_refcount_tree *ref_tree; | ||
6744 | struct buffer_head *ref_root_bh = NULL; | ||
6745 | |||
6746 | ret = ocfs2_lock_refcount_tree(OCFS2_SB(old_inode->i_sb), | ||
6747 | le64_to_cpu(di->i_refcount_loc), | ||
6748 | 1, &ref_tree, &ref_root_bh); | ||
6749 | if (ret) { | ||
6750 | mlog_errno(ret); | ||
6751 | goto out; | ||
6752 | } | ||
6753 | |||
6754 | ocfs2_init_dealloc_ctxt(&dealloc); | ||
6755 | |||
6756 | args.old_inode = old_inode; | ||
6757 | args.new_inode = new_inode; | ||
6758 | args.old_bh = old_bh; | ||
6759 | args.new_bh = new_bh; | ||
6760 | args.ref_ci = &ref_tree->rf_ci; | ||
6761 | args.ref_root_bh = ref_root_bh; | ||
6762 | args.dealloc = &dealloc; | ||
6763 | |||
6764 | if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) { | ||
6765 | ret = ocfs2_reflink_xattr_inline(&args); | ||
6766 | if (ret) { | ||
6767 | mlog_errno(ret); | ||
6768 | goto out_unlock; | ||
6769 | } | ||
6770 | } | ||
6771 | |||
6772 | if (!di->i_xattr_loc) | ||
6773 | goto out_unlock; | ||
6774 | |||
6775 | ret = ocfs2_read_xattr_block(old_inode, le64_to_cpu(di->i_xattr_loc), | ||
6776 | &blk_bh); | ||
6777 | if (ret < 0) { | ||
6778 | mlog_errno(ret); | ||
6779 | goto out_unlock; | ||
6780 | } | ||
6781 | |||
6782 | ret = ocfs2_reflink_xattr_in_block(&args, blk_bh); | ||
6783 | if (ret) | ||
6784 | mlog_errno(ret); | ||
6785 | |||
6786 | brelse(blk_bh); | ||
6787 | |||
6788 | out_unlock: | ||
6789 | ocfs2_unlock_refcount_tree(OCFS2_SB(old_inode->i_sb), | ||
6790 | ref_tree, 1); | ||
6791 | brelse(ref_root_bh); | ||
6792 | |||
6793 | if (ocfs2_dealloc_has_cluster(&dealloc)) { | ||
6794 | ocfs2_schedule_truncate_log_flush(OCFS2_SB(old_inode->i_sb), 1); | ||
6795 | ocfs2_run_deallocs(OCFS2_SB(old_inode->i_sb), &dealloc); | ||
6796 | } | ||
6797 | |||
6798 | out: | ||
6799 | return ret; | ||
6800 | } | ||
6801 | |||
6802 | /* | ||
5880 | * 'security' attributes support | 6803 | * 'security' attributes support |
5881 | */ | 6804 | */ |
5882 | static size_t ocfs2_xattr_security_list(struct inode *inode, char *list, | 6805 | static size_t ocfs2_xattr_security_list(struct inode *inode, char *list, |
diff --git a/fs/ocfs2/xattr.h b/fs/ocfs2/xattr.h index e74703f56dca..4f913053d5ee 100644 --- a/fs/ocfs2/xattr.h +++ b/fs/ocfs2/xattr.h | |||
@@ -90,4 +90,8 @@ int ocfs2_xattr_attach_refcount_tree(struct inode *inode, | |||
90 | struct ocfs2_caching_info *ref_ci, | 90 | struct ocfs2_caching_info *ref_ci, |
91 | struct buffer_head *ref_root_bh, | 91 | struct buffer_head *ref_root_bh, |
92 | struct ocfs2_cached_dealloc_ctxt *dealloc); | 92 | struct ocfs2_cached_dealloc_ctxt *dealloc); |
93 | int ocfs2_reflink_xattrs(struct inode *old_inode, | ||
94 | struct buffer_head *old_bh, | ||
95 | struct inode *new_inode, | ||
96 | struct buffer_head *new_bh); | ||
93 | #endif /* OCFS2_XATTR_H */ | 97 | #endif /* OCFS2_XATTR_H */ |