aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
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,