We currently use pagecache to duplicate clusters in CoW,
but it isn't suitable for xattr case. So abstract it out
so that the caller can decide which method it use.

Signed-off-by: Tao Ma <[email protected]>
---
 fs/ocfs2/refcounttree.c |  141 ++++++++++++++++++++++++++---------------------
 1 files changed, 79 insertions(+), 62 deletions(-)

diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c
index a12d739..0f94619 100644
--- a/fs/ocfs2/refcounttree.c
+++ b/fs/ocfs2/refcounttree.c
@@ -41,7 +41,7 @@
 
 struct ocfs2_cow_context {
        struct inode *inode;
-       struct ocfs2_extent_tree di_et;
+       struct ocfs2_extent_tree data_et;
        struct ocfs2_caching_info *ref_ci;
        struct buffer_head *ref_root_bh;
        struct ocfs2_alloc_context *meta_ac;
@@ -52,6 +52,14 @@ struct ocfs2_cow_context {
        int num_pages;
        u32 cow_start;
        u32 cow_len;
+       int (*get_clusters)(struct ocfs2_cow_context *context,
+                           u32 v_cluster, u32 *p_cluster,
+                           u32 *num_clusters,
+                           unsigned int *extent_flags);
+       int (*cow_duplicate_clusters)(handle_t *handle,
+                                     struct ocfs2_cow_context *context,
+                                     u32 cpos, u32 old_cluster,
+                                     u32 new_cluster, u32 new_len);
 };
 
 static const struct ocfs2_caching_operations ocfs2_refcount_caching_ops;
@@ -1830,7 +1838,7 @@ out:
  * use that value as the maximum clusters.
  */
 static int ocfs2_refcount_cal_cow_clusters(struct inode *inode,
-                                          struct buffer_head *di_bh,
+                                          struct ocfs2_extent_list *el,
                                           u32 cpos,
                                           u32 write_len,
                                           u32 *cow_start,
@@ -1838,8 +1846,6 @@ static int ocfs2_refcount_cal_cow_clusters(struct inode 
*inode,
                                           int *has_data)
 {
        int ret = 0;
-       struct ocfs2_dinode *di = (struct ocfs2_dinode *) di_bh->b_data;
-       struct ocfs2_extent_list *el = &di->id2.i_list;
        int tree_height = le16_to_cpu(el->l_tree_depth), i;
        struct buffer_head *eb_bh = NULL;
        struct ocfs2_extent_block *eb = NULL;
@@ -2091,13 +2097,13 @@ out:
        return ret;
 }
 
-static int ocfs2_duplicate_clusters(handle_t *handle,
-                                   struct ocfs2_cow_context *context,
-                                   u32 cpos, u32 old_cluster,
-                                   u32 new_cluster, u32 new_len)
+static int ocfs2_duplicate_clusters_by_page(handle_t *handle,
+                                           struct ocfs2_cow_context *context,
+                                           u32 cpos, u32 old_cluster,
+                                           u32 new_cluster, u32 new_len)
 {
        int ret = 0, bh_num;
-       struct ocfs2_caching_info *ci = context->di_et.et_ci;
+       struct ocfs2_caching_info *ci = context->data_et.et_ci;
        struct super_block *sb = ocfs2_metadata_cache_get_super(ci);
        int i, j, bpc = ocfs2_clusters_to_blocks(sb, 1);
        u64 old_block = ocfs2_clusters_to_blocks(sb, old_cluster);
@@ -2235,7 +2241,7 @@ static int ocfs2_replace_clusters(handle_t *handle,
                                  unsigned int ext_flags)
 {
        int ret;
-       struct ocfs2_caching_info *ci = context->di_et.et_ci;
+       struct ocfs2_caching_info *ci = context->data_et.et_ci;
        u64 ino = ocfs2_metadata_cache_owner(ci);
 
        mlog(0, "inode %llu, cpos %u, old %u, new %u, len %u, ext_flags %u\n",
@@ -2243,15 +2249,15 @@ static int ocfs2_replace_clusters(handle_t *handle,
 
        /*If the old clusters is unwritten, no need to duplicate. */
        if (!(ext_flags & OCFS2_EXT_UNWRITTEN)) {
-               ret = ocfs2_duplicate_clusters(handle, context, cpos,
-                                              old, new, len);
+               ret = context->cow_duplicate_clusters(handle, context, cpos,
+                                                     old, new, len);
                if (ret) {
                        mlog_errno(ret);
                        goto out;
                }
        }
 
-       ret = ocfs2_clear_ext_refcount(handle, &context->di_et,
+       ret = ocfs2_clear_ext_refcount(handle, &context->data_et,
                                       cpos, new, len, ext_flags,
                                       context->meta_ac, &context->dealloc);
        if (ret)
@@ -2277,7 +2283,7 @@ static int ocfs2_make_clusters_writable(struct 
super_block *sb,
             cpos, p_cluster, num_clusters, e_flags);
 
        ret = ocfs2_lock_refcount_allocators(sb, p_cluster, num_clusters,
-                                            &context->di_et,
+                                            &context->data_et,
                                             context->ref_ci,
                                             context->ref_root_bh,
                                             &context->meta_ac,
@@ -2318,7 +2324,8 @@ static int ocfs2_make_clusters_writable(struct 
super_block *sb,
                 */
                if (le32_to_cpu(rec.r_refcount) == 1) {
                        delete = 0;
-                       ret = ocfs2_clear_ext_refcount(handle, &context->di_et,
+                       ret = ocfs2_clear_ext_refcount(handle,
+                                                      &context->data_et,
                                                       cpos, p_cluster,
                                                       set_len, e_flags,
                                                       context->meta_ac,
@@ -2382,19 +2389,25 @@ out:
        return ret;
 }
 
-static int ocfs2_replace_cow(struct inode *inode,
-                            struct buffer_head *di_bh,
-                            struct buffer_head *ref_root_bh,
-                            struct ocfs2_caching_info *ref_ci,
-                            u32 cow_start, u32 cow_len,
-                            struct page **pages,
-                            int num_pages)
+static int ocfs2_di_get_clusters(struct ocfs2_cow_context *context,
+                                u32 v_cluster, u32 *p_cluster,
+                                u32 *num_clusters,
+                                unsigned int *extent_flags)
+{
+       struct inode *inode = context->inode;
+
+       return ocfs2_get_clusters(inode, v_cluster, p_cluster,
+                                 num_clusters, extent_flags);
+}
+
+static int ocfs2_replace_cow(struct ocfs2_cow_context *context)
 {
        int ret;
-       u32 p_cluster, num_clusters, start = cow_start;
+       struct inode *inode = context->inode;
+       u32 cow_start = context->cow_start, cow_len = context->cow_len;
+       u32 p_cluster, num_clusters;
        unsigned int ext_flags;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
-       struct ocfs2_cow_context context;
 
        if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb))) {
                ocfs2_error(inode->i_sb, "Inode %lu want to use refcount "
@@ -2403,38 +2416,18 @@ static int ocfs2_replace_cow(struct inode *inode,
                return -EROFS;
        }
 
-       memset(&context, 0, sizeof(context));
-
-       context.inode = inode;
-       context.cow_pages = pages;
-       context.num_pages = num_pages;
-       context.cow_start = cow_start;
-       context.cow_len = cow_len;
-       context.ref_ci = ref_ci;
-       context.ref_root_bh = ref_root_bh;
-
-       context.bhs = kcalloc(ocfs2_clusters_to_blocks(inode->i_sb, 1),
-                             sizeof(struct buffer_head *), GFP_NOFS);
-       if (!context.bhs) {
-               ret = -ENOMEM;
-               mlog_errno(ret);
-               return ret;
-       }
-
-       ocfs2_init_dealloc_ctxt(&context.dealloc);
-       ocfs2_init_dinode_extent_tree(&context.di_et,
-                                     INODE_CACHE(inode), di_bh);
+       ocfs2_init_dealloc_ctxt(&context->dealloc);
 
        while (cow_len) {
-               ret = ocfs2_get_clusters(inode, cow_start, &p_cluster,
-                                        &num_clusters, &ext_flags);
+               ret = context->get_clusters(context, cow_start, &p_cluster,
+                                           &num_clusters, &ext_flags);
 
                BUG_ON(!(ext_flags & OCFS2_EXT_REFCOUNTED));
 
                if (cow_len < num_clusters)
                        num_clusters = cow_len;
 
-               ret = ocfs2_make_clusters_writable(inode->i_sb, &context,
+               ret = ocfs2_make_clusters_writable(inode->i_sb, context,
                                                   cow_start, p_cluster,
                                                   num_clusters, ext_flags);
                if (ret) {
@@ -2446,20 +2439,11 @@ static int ocfs2_replace_cow(struct inode *inode,
                cow_start += num_clusters;
        }
 
-
-       /*
-        * truncate the extent map here since no matter whether we meet with
-        * any error during the action, we shouldn't trust cached extent map
-        * any more.
-        */
-       ocfs2_extent_map_trunc(inode, start);
-
-       if (ocfs2_dealloc_has_cluster(&context.dealloc)) {
+       if (ocfs2_dealloc_has_cluster(&context->dealloc)) {
                ocfs2_schedule_truncate_log_flush(osb, 1);
-               ocfs2_run_deallocs(osb, &context.dealloc);
+               ocfs2_run_deallocs(osb, &context->dealloc);
        }
 
-       kfree(context.bhs);
        return ret;
 }
 
@@ -2476,11 +2460,15 @@ int ocfs2_refcount_cow(struct inode *inode,
        struct page **pages = NULL;
        struct ocfs2_refcount_tree *ref_tree;
        loff_t start, end;
+       struct ocfs2_cow_context context;
+
+       memset(&context, 0, sizeof(context));
 
        BUG_ON(!(oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL));
        BUG_ON(!di->i_refcount_loc);
 
-       ret = ocfs2_refcount_cal_cow_clusters(inode, di_bh, cpos, write_len,
+       ret = ocfs2_refcount_cal_cow_clusters(inode, &di->id2.i_list,
+                                             cpos, write_len,
                                              &cow_start, &cow_len, &has_data);
        if (ret) {
                mlog_errno(ret);
@@ -2518,11 +2506,40 @@ int ocfs2_refcount_cow(struct inode *inode,
                goto out;
        }
 
-       ret = ocfs2_replace_cow(inode, di_bh, ref_root_bh, &ref_tree->rf_ci,
-                               cow_start, cow_len, pages, num_pages);
+       context.inode = inode;
+       context.cow_start = cow_start;
+       context.cow_len = cow_len;
+       context.ref_ci = &ref_tree->rf_ci;
+       context.ref_root_bh = ref_root_bh;
+       context.cow_pages = pages;
+       context.num_pages = num_pages;
+       context.bhs = kcalloc(ocfs2_clusters_to_blocks(inode->i_sb, 1),
+                             sizeof(struct buffer_head *), GFP_NOFS);
+       if (!context.bhs) {
+               ret = -ENOMEM;
+               mlog_errno(ret);
+               goto out_unlock;
+       }
+
+       context.cow_duplicate_clusters = ocfs2_duplicate_clusters_by_page;
+       context.get_clusters = ocfs2_di_get_clusters;
+
+       ocfs2_init_dinode_extent_tree(&context.data_et,
+                                     INODE_CACHE(inode), di_bh);
+
+       ret = ocfs2_replace_cow(&context);
        if (ret)
                mlog_errno(ret);
 
+       /*
+        * truncate the extent map here since no matter whether we meet with
+        * any error during the action, we shouldn't trust cached extent map
+        * any more.
+        */
+       ocfs2_extent_map_trunc(inode, cow_start);
+
+       kfree(context.bhs);
+out_unlock:
        ocfs2_unlock_refcount_tree(osb, ref_tree, 1);
        brelse(ref_root_bh);
 out:
-- 
1.6.2.rc2.16.gf474c


_______________________________________________
Ocfs2-devel mailing list
[email protected]
http://oss.oracle.com/mailman/listinfo/ocfs2-devel

Reply via email to