aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorTao Ma <tao.ma@oracle.com>2009-08-17 23:30:55 -0400
committerJoel Becker <joel.becker@oracle.com>2009-09-22 23:09:36 -0400
commit6ae23c5555176c5b23480c9c578ff27437085ba5 (patch)
tree4afb1c33e850fa751c6136d65a041f70fe146fe8 /fs
parent6f70fa519976a379d72781d927cf8e5f5b05ec86 (diff)
ocfs2: CoW refcount tree improvement.
During CoW, if the old extent record is refcounted, we allocate som new clusters and do CoW. Actually we can have some improvement here. If the old extent has refcount=1, that means now it is only used by this file. So we don't need to allocate new clusters, just remove the refcounted flag and it is OK. We also have to remove it from the refcount tree while not deleting it. Signed-off-by: Tao Ma <tao.ma@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/ocfs2/alloc.c2
-rw-r--r--fs/ocfs2/refcounttree.c104
-rw-r--r--fs/ocfs2/refcounttree.h3
3 files changed, 81 insertions, 28 deletions
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c
index b8fc95d10630..7c879fc7834f 100644
--- a/fs/ocfs2/alloc.c
+++ b/fs/ocfs2/alloc.c
@@ -6974,7 +6974,7 @@ static int ocfs2_do_truncate(struct ocfs2_super *osb,
6974 ocfs2_blocks_to_clusters(osb->sb, 6974 ocfs2_blocks_to_clusters(osb->sb,
6975 delete_blk), 6975 delete_blk),
6976 clusters_to_del, meta_ac, 6976 clusters_to_del, meta_ac,
6977 &tc->tc_dealloc); 6977 &tc->tc_dealloc, 1);
6978 else 6978 else
6979 status = ocfs2_truncate_log_append(osb, handle, 6979 status = ocfs2_truncate_log_append(osb, handle,
6980 delete_blk, 6980 delete_blk,
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c
index 4e7df8b8fd4f..0a92436557e3 100644
--- a/fs/ocfs2/refcounttree.c
+++ b/fs/ocfs2/refcounttree.c
@@ -2076,7 +2076,8 @@ static int __ocfs2_decrease_refcount(handle_t *handle,
2076 struct buffer_head *ref_root_bh, 2076 struct buffer_head *ref_root_bh,
2077 u64 cpos, u32 len, 2077 u64 cpos, u32 len,
2078 struct ocfs2_alloc_context *meta_ac, 2078 struct ocfs2_alloc_context *meta_ac,
2079 struct ocfs2_cached_dealloc_ctxt *dealloc) 2079 struct ocfs2_cached_dealloc_ctxt *dealloc,
2080 int delete)
2080{ 2081{
2081 int ret = 0, index = 0; 2082 int ret = 0, index = 0;
2082 struct ocfs2_refcount_rec rec; 2083 struct ocfs2_refcount_rec rec;
@@ -2084,9 +2085,10 @@ static int __ocfs2_decrease_refcount(handle_t *handle,
2084 struct super_block *sb = ocfs2_metadata_cache_get_super(ci); 2085 struct super_block *sb = ocfs2_metadata_cache_get_super(ci);
2085 struct buffer_head *ref_leaf_bh = NULL; 2086 struct buffer_head *ref_leaf_bh = NULL;
2086 2087
2087 mlog(0, "Tree owner %llu, decrease refcount start %llu, len %u\n", 2088 mlog(0, "Tree owner %llu, decrease refcount start %llu, "
2089 "len %u, delete %u\n",
2088 (unsigned long long)ocfs2_metadata_cache_owner(ci), 2090 (unsigned long long)ocfs2_metadata_cache_owner(ci),
2089 (unsigned long long)cpos, len); 2091 (unsigned long long)cpos, len, delete);
2090 2092
2091 while (len) { 2093 while (len) {
2092 ret = ocfs2_get_refcount_rec(ci, ref_root_bh, 2094 ret = ocfs2_get_refcount_rec(ci, ref_root_bh,
@@ -2099,6 +2101,8 @@ static int __ocfs2_decrease_refcount(handle_t *handle,
2099 2101
2100 r_count = le32_to_cpu(rec.r_refcount); 2102 r_count = le32_to_cpu(rec.r_refcount);
2101 BUG_ON(r_count == 0); 2103 BUG_ON(r_count == 0);
2104 if (!delete)
2105 BUG_ON(r_count > 1);
2102 2106
2103 r_len = min((u64)(cpos + len), le64_to_cpu(rec.r_cpos) + 2107 r_len = min((u64)(cpos + len), le64_to_cpu(rec.r_cpos) +
2104 le32_to_cpu(rec.r_clusters)) - cpos; 2108 le32_to_cpu(rec.r_clusters)) - cpos;
@@ -2112,7 +2116,7 @@ static int __ocfs2_decrease_refcount(handle_t *handle,
2112 goto out; 2116 goto out;
2113 } 2117 }
2114 2118
2115 if (le32_to_cpu(rec.r_refcount) == 1) { 2119 if (le32_to_cpu(rec.r_refcount) == 1 && delete) {
2116 ret = ocfs2_cache_cluster_dealloc(dealloc, 2120 ret = ocfs2_cache_cluster_dealloc(dealloc,
2117 ocfs2_clusters_to_blocks(sb, cpos), 2121 ocfs2_clusters_to_blocks(sb, cpos),
2118 r_len); 2122 r_len);
@@ -2137,7 +2141,8 @@ out:
2137int ocfs2_decrease_refcount(struct inode *inode, 2141int ocfs2_decrease_refcount(struct inode *inode,
2138 handle_t *handle, u32 cpos, u32 len, 2142 handle_t *handle, u32 cpos, u32 len,
2139 struct ocfs2_alloc_context *meta_ac, 2143 struct ocfs2_alloc_context *meta_ac,
2140 struct ocfs2_cached_dealloc_ctxt *dealloc) 2144 struct ocfs2_cached_dealloc_ctxt *dealloc,
2145 int delete)
2141{ 2146{
2142 int ret; 2147 int ret;
2143 u64 ref_blkno; 2148 u64 ref_blkno;
@@ -2167,7 +2172,7 @@ int ocfs2_decrease_refcount(struct inode *inode,
2167 } 2172 }
2168 2173
2169 ret = __ocfs2_decrease_refcount(handle, &tree->rf_ci, ref_root_bh, 2174 ret = __ocfs2_decrease_refcount(handle, &tree->rf_ci, ref_root_bh,
2170 cpos, len, meta_ac, dealloc); 2175 cpos, len, meta_ac, dealloc, delete);
2171 if (ret) 2176 if (ret)
2172 mlog_errno(ret); 2177 mlog_errno(ret);
2173out: 2178out:
@@ -2974,10 +2979,16 @@ static int ocfs2_make_clusters_writable(struct super_block *sb,
2974 u32 cpos, u32 p_cluster, 2979 u32 cpos, u32 p_cluster,
2975 u32 num_clusters, unsigned int e_flags) 2980 u32 num_clusters, unsigned int e_flags)
2976{ 2981{
2977 int ret, credits = 0; 2982 int ret, delete, index, credits = 0;
2978 u32 new_bit, new_len; 2983 u32 new_bit, new_len;
2984 unsigned int set_len;
2979 struct ocfs2_super *osb = OCFS2_SB(sb); 2985 struct ocfs2_super *osb = OCFS2_SB(sb);
2980 handle_t *handle; 2986 handle_t *handle;
2987 struct buffer_head *ref_leaf_bh = NULL;
2988 struct ocfs2_refcount_rec rec;
2989
2990 mlog(0, "cpos %u, p_cluster %u, num_clusters %u, e_flags %u\n",
2991 cpos, p_cluster, num_clusters, e_flags);
2981 2992
2982 ret = ocfs2_lock_refcount_allocators(sb, p_cluster, num_clusters, 2993 ret = ocfs2_lock_refcount_allocators(sb, p_cluster, num_clusters,
2983 &context->di_et, 2994 &context->di_et,
@@ -2998,35 +3009,75 @@ static int ocfs2_make_clusters_writable(struct super_block *sb,
2998 } 3009 }
2999 3010
3000 while (num_clusters) { 3011 while (num_clusters) {
3001 ret = __ocfs2_claim_clusters(osb, handle, context->data_ac, 3012 ret = ocfs2_get_refcount_rec(context->ref_ci,
3002 1, num_clusters, 3013 context->ref_root_bh,
3003 &new_bit, &new_len); 3014 p_cluster, num_clusters,
3015 &rec, &index, &ref_leaf_bh);
3004 if (ret) { 3016 if (ret) {
3005 mlog_errno(ret); 3017 mlog_errno(ret);
3006 goto out_commit; 3018 goto out_commit;
3007 } 3019 }
3008 3020
3009 ret = ocfs2_replace_clusters(handle, context, 3021 BUG_ON(!rec.r_refcount);
3010 cpos, p_cluster, new_bit, 3022 set_len = min((u64)p_cluster + num_clusters,
3011 new_len, e_flags); 3023 le64_to_cpu(rec.r_cpos) +
3024 le32_to_cpu(rec.r_clusters)) - p_cluster;
3025
3026 /*
3027 * There are many different situation here.
3028 * 1. If refcount == 1, remove the flag and don't COW.
3029 * 2. If refcount > 1, allocate clusters.
3030 * Here we may not allocate r_len once at a time, so continue
3031 * until we reach num_clusters.
3032 */
3033 if (le32_to_cpu(rec.r_refcount) == 1) {
3034 delete = 0;
3035 ret = ocfs2_clear_ext_refcount(handle, &context->di_et,
3036 cpos, p_cluster,
3037 set_len, e_flags,
3038 context->meta_ac,
3039 &context->dealloc);
3040 if (ret) {
3041 mlog_errno(ret);
3042 goto out_commit;
3043 }
3044 } else {
3045 delete = 1;
3046
3047 ret = __ocfs2_claim_clusters(osb, handle,
3048 context->data_ac,
3049 1, set_len,
3050 &new_bit, &new_len);
3051 if (ret) {
3052 mlog_errno(ret);
3053 goto out_commit;
3054 }
3055
3056 ret = ocfs2_replace_clusters(handle, context,
3057 cpos, p_cluster, new_bit,
3058 new_len, e_flags);
3059 if (ret) {
3060 mlog_errno(ret);
3061 goto out_commit;
3062 }
3063 set_len = new_len;
3064 }
3065
3066 ret = __ocfs2_decrease_refcount(handle, context->ref_ci,
3067 context->ref_root_bh,
3068 p_cluster, set_len,
3069 context->meta_ac,
3070 &context->dealloc, delete);
3012 if (ret) { 3071 if (ret) {
3013 mlog_errno(ret); 3072 mlog_errno(ret);
3014 goto out_commit; 3073 goto out_commit;
3015 } 3074 }
3016 3075
3017 cpos += new_len; 3076 cpos += set_len;
3018 p_cluster += new_len; 3077 p_cluster += set_len;
3019 num_clusters -= new_len; 3078 num_clusters -= set_len;
3020 } 3079 brelse(ref_leaf_bh);
3021 3080 ref_leaf_bh = NULL;
3022 ret = __ocfs2_decrease_refcount(handle, context->ref_ci,
3023 context->ref_root_bh,
3024 p_cluster, num_clusters,
3025 context->meta_ac,
3026 &context->dealloc);
3027 if (ret) {
3028 mlog_errno(ret);
3029 goto out_commit;
3030 } 3081 }
3031 3082
3032 /* 3083 /*
@@ -3049,6 +3100,7 @@ out:
3049 ocfs2_free_alloc_context(context->meta_ac); 3100 ocfs2_free_alloc_context(context->meta_ac);
3050 context->meta_ac = NULL; 3101 context->meta_ac = NULL;
3051 } 3102 }
3103 brelse(ref_leaf_bh);
3052 3104
3053 return ret; 3105 return ret;
3054} 3106}
diff --git a/fs/ocfs2/refcounttree.h b/fs/ocfs2/refcounttree.h
index 9960878134df..a8c15b0b2307 100644
--- a/fs/ocfs2/refcounttree.h
+++ b/fs/ocfs2/refcounttree.h
@@ -44,7 +44,8 @@ void ocfs2_unlock_refcount_tree(struct ocfs2_super *osb,
44int ocfs2_decrease_refcount(struct inode *inode, 44int ocfs2_decrease_refcount(struct inode *inode,
45 handle_t *handle, u32 cpos, u32 len, 45 handle_t *handle, u32 cpos, u32 len,
46 struct ocfs2_alloc_context *meta_ac, 46 struct ocfs2_alloc_context *meta_ac,
47 struct ocfs2_cached_dealloc_ctxt *dealloc); 47 struct ocfs2_cached_dealloc_ctxt *dealloc,
48 int delete);
48int ocfs2_prepare_refcount_change_for_del(struct inode *inode, 49int ocfs2_prepare_refcount_change_for_del(struct inode *inode,
49 struct buffer_head *di_bh, 50 struct buffer_head *di_bh,
50 u64 phys_blkno, 51 u64 phys_blkno,