|
@@ -2076,7 +2076,8 @@ static int __ocfs2_decrease_refcount(handle_t *handle,
|
|
|
struct buffer_head *ref_root_bh,
|
|
|
u64 cpos, u32 len,
|
|
|
struct ocfs2_alloc_context *meta_ac,
|
|
|
- struct ocfs2_cached_dealloc_ctxt *dealloc)
|
|
|
+ struct ocfs2_cached_dealloc_ctxt *dealloc,
|
|
|
+ int delete)
|
|
|
{
|
|
|
int ret = 0, index = 0;
|
|
|
struct ocfs2_refcount_rec rec;
|
|
@@ -2084,9 +2085,10 @@ static int __ocfs2_decrease_refcount(handle_t *handle,
|
|
|
struct super_block *sb = ocfs2_metadata_cache_get_super(ci);
|
|
|
struct buffer_head *ref_leaf_bh = NULL;
|
|
|
|
|
|
- mlog(0, "Tree owner %llu, decrease refcount start %llu, len %u\n",
|
|
|
+ mlog(0, "Tree owner %llu, decrease refcount start %llu, "
|
|
|
+ "len %u, delete %u\n",
|
|
|
(unsigned long long)ocfs2_metadata_cache_owner(ci),
|
|
|
- (unsigned long long)cpos, len);
|
|
|
+ (unsigned long long)cpos, len, delete);
|
|
|
|
|
|
while (len) {
|
|
|
ret = ocfs2_get_refcount_rec(ci, ref_root_bh,
|
|
@@ -2099,6 +2101,8 @@ static int __ocfs2_decrease_refcount(handle_t *handle,
|
|
|
|
|
|
r_count = le32_to_cpu(rec.r_refcount);
|
|
|
BUG_ON(r_count == 0);
|
|
|
+ if (!delete)
|
|
|
+ BUG_ON(r_count > 1);
|
|
|
|
|
|
r_len = min((u64)(cpos + len), le64_to_cpu(rec.r_cpos) +
|
|
|
le32_to_cpu(rec.r_clusters)) - cpos;
|
|
@@ -2112,7 +2116,7 @@ static int __ocfs2_decrease_refcount(handle_t *handle,
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- if (le32_to_cpu(rec.r_refcount) == 1) {
|
|
|
+ if (le32_to_cpu(rec.r_refcount) == 1 && delete) {
|
|
|
ret = ocfs2_cache_cluster_dealloc(dealloc,
|
|
|
ocfs2_clusters_to_blocks(sb, cpos),
|
|
|
r_len);
|
|
@@ -2137,7 +2141,8 @@ out:
|
|
|
int ocfs2_decrease_refcount(struct inode *inode,
|
|
|
handle_t *handle, u32 cpos, u32 len,
|
|
|
struct ocfs2_alloc_context *meta_ac,
|
|
|
- struct ocfs2_cached_dealloc_ctxt *dealloc)
|
|
|
+ struct ocfs2_cached_dealloc_ctxt *dealloc,
|
|
|
+ int delete)
|
|
|
{
|
|
|
int ret;
|
|
|
u64 ref_blkno;
|
|
@@ -2167,7 +2172,7 @@ int ocfs2_decrease_refcount(struct inode *inode,
|
|
|
}
|
|
|
|
|
|
ret = __ocfs2_decrease_refcount(handle, &tree->rf_ci, ref_root_bh,
|
|
|
- cpos, len, meta_ac, dealloc);
|
|
|
+ cpos, len, meta_ac, dealloc, delete);
|
|
|
if (ret)
|
|
|
mlog_errno(ret);
|
|
|
out:
|
|
@@ -2974,10 +2979,16 @@ static int ocfs2_make_clusters_writable(struct super_block *sb,
|
|
|
u32 cpos, u32 p_cluster,
|
|
|
u32 num_clusters, unsigned int e_flags)
|
|
|
{
|
|
|
- int ret, credits = 0;
|
|
|
+ int ret, delete, index, credits = 0;
|
|
|
u32 new_bit, new_len;
|
|
|
+ unsigned int set_len;
|
|
|
struct ocfs2_super *osb = OCFS2_SB(sb);
|
|
|
handle_t *handle;
|
|
|
+ struct buffer_head *ref_leaf_bh = NULL;
|
|
|
+ struct ocfs2_refcount_rec rec;
|
|
|
+
|
|
|
+ mlog(0, "cpos %u, p_cluster %u, num_clusters %u, e_flags %u\n",
|
|
|
+ cpos, p_cluster, num_clusters, e_flags);
|
|
|
|
|
|
ret = ocfs2_lock_refcount_allocators(sb, p_cluster, num_clusters,
|
|
|
&context->di_et,
|
|
@@ -2998,35 +3009,75 @@ static int ocfs2_make_clusters_writable(struct super_block *sb,
|
|
|
}
|
|
|
|
|
|
while (num_clusters) {
|
|
|
- ret = __ocfs2_claim_clusters(osb, handle, context->data_ac,
|
|
|
- 1, num_clusters,
|
|
|
- &new_bit, &new_len);
|
|
|
+ ret = ocfs2_get_refcount_rec(context->ref_ci,
|
|
|
+ context->ref_root_bh,
|
|
|
+ p_cluster, num_clusters,
|
|
|
+ &rec, &index, &ref_leaf_bh);
|
|
|
if (ret) {
|
|
|
mlog_errno(ret);
|
|
|
goto out_commit;
|
|
|
}
|
|
|
|
|
|
- ret = ocfs2_replace_clusters(handle, context,
|
|
|
- cpos, p_cluster, new_bit,
|
|
|
- new_len, e_flags);
|
|
|
+ BUG_ON(!rec.r_refcount);
|
|
|
+ set_len = min((u64)p_cluster + num_clusters,
|
|
|
+ le64_to_cpu(rec.r_cpos) +
|
|
|
+ le32_to_cpu(rec.r_clusters)) - p_cluster;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * There are many different situation here.
|
|
|
+ * 1. If refcount == 1, remove the flag and don't COW.
|
|
|
+ * 2. If refcount > 1, allocate clusters.
|
|
|
+ * Here we may not allocate r_len once at a time, so continue
|
|
|
+ * until we reach num_clusters.
|
|
|
+ */
|
|
|
+ if (le32_to_cpu(rec.r_refcount) == 1) {
|
|
|
+ delete = 0;
|
|
|
+ ret = ocfs2_clear_ext_refcount(handle, &context->di_et,
|
|
|
+ cpos, p_cluster,
|
|
|
+ set_len, e_flags,
|
|
|
+ context->meta_ac,
|
|
|
+ &context->dealloc);
|
|
|
+ if (ret) {
|
|
|
+ mlog_errno(ret);
|
|
|
+ goto out_commit;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ delete = 1;
|
|
|
+
|
|
|
+ ret = __ocfs2_claim_clusters(osb, handle,
|
|
|
+ context->data_ac,
|
|
|
+ 1, set_len,
|
|
|
+ &new_bit, &new_len);
|
|
|
+ if (ret) {
|
|
|
+ mlog_errno(ret);
|
|
|
+ goto out_commit;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = ocfs2_replace_clusters(handle, context,
|
|
|
+ cpos, p_cluster, new_bit,
|
|
|
+ new_len, e_flags);
|
|
|
+ if (ret) {
|
|
|
+ mlog_errno(ret);
|
|
|
+ goto out_commit;
|
|
|
+ }
|
|
|
+ set_len = new_len;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = __ocfs2_decrease_refcount(handle, context->ref_ci,
|
|
|
+ context->ref_root_bh,
|
|
|
+ p_cluster, set_len,
|
|
|
+ context->meta_ac,
|
|
|
+ &context->dealloc, delete);
|
|
|
if (ret) {
|
|
|
mlog_errno(ret);
|
|
|
goto out_commit;
|
|
|
}
|
|
|
|
|
|
- cpos += new_len;
|
|
|
- p_cluster += new_len;
|
|
|
- num_clusters -= new_len;
|
|
|
- }
|
|
|
-
|
|
|
- ret = __ocfs2_decrease_refcount(handle, context->ref_ci,
|
|
|
- context->ref_root_bh,
|
|
|
- p_cluster, num_clusters,
|
|
|
- context->meta_ac,
|
|
|
- &context->dealloc);
|
|
|
- if (ret) {
|
|
|
- mlog_errno(ret);
|
|
|
- goto out_commit;
|
|
|
+ cpos += set_len;
|
|
|
+ p_cluster += set_len;
|
|
|
+ num_clusters -= set_len;
|
|
|
+ brelse(ref_leaf_bh);
|
|
|
+ ref_leaf_bh = NULL;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -3049,6 +3100,7 @@ out:
|
|
|
ocfs2_free_alloc_context(context->meta_ac);
|
|
|
context->meta_ac = NULL;
|
|
|
}
|
|
|
+ brelse(ref_leaf_bh);
|
|
|
|
|
|
return ret;
|
|
|
}
|