diff options
Diffstat (limited to 'fs/ocfs2/refcounttree.c')
-rw-r--r-- | fs/ocfs2/refcounttree.c | 104 |
1 files changed, 78 insertions, 26 deletions
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: | |||
2137 | int ocfs2_decrease_refcount(struct inode *inode, | 2141 | int 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); |
2173 | out: | 2178 | out: |
@@ -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 | } |