[Ocfs2-devel] [PATCH 16/42] ocfs2: Hook 'Decrement refcount for delete'.

Tao Ma tao.ma at oracle.com
Thu Mar 26 16:02:22 PDT 2009


Add 'Decrement refcount for delete' in to the normal truncate
process. So for a refcounted extent record, call refcount rec
decrementation instead of cluster free.

Signed-off-by: Tao Ma <tao.ma at oracle.com>
---
 fs/ocfs2/alloc.c        |   48 ++++++++++++++++---
 fs/ocfs2/refcounttree.c |  118 +++++++++++++++++++++++++++++++++++++++++++++++
 fs/ocfs2/refcounttree.h |    4 ++
 3 files changed, 163 insertions(+), 7 deletions(-)

diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c
index bbfb15a..d557d49 100644
--- a/fs/ocfs2/alloc.c
+++ b/fs/ocfs2/alloc.c
@@ -6592,7 +6592,7 @@ out:
  */
 static int ocfs2_trim_tree(struct inode *inode, struct ocfs2_path *path,
 			   handle_t *handle, struct ocfs2_truncate_context *tc,
-			   u32 clusters_to_del, u64 *delete_start)
+			   u32 clusters_to_del, u64 *delete_start, u8 *flags)
 {
 	int ret, i, index = path->p_tree_depth;
 	u32 new_edge = 0;
@@ -6602,6 +6602,7 @@ static int ocfs2_trim_tree(struct inode *inode, struct ocfs2_path *path,
 	struct ocfs2_extent_rec *rec;
 
 	*delete_start = 0;
+	*flags = 0;
 
 	while (index >= 0) {
 		bh = path->p_node[index].bh;
@@ -6689,6 +6690,7 @@ find_tail_record:
 			*delete_start = le64_to_cpu(rec->e_blkno)
 				+ ocfs2_clusters_to_blocks(inode->i_sb,
 					le16_to_cpu(rec->e_leaf_clusters));
+			*flags = rec->e_flags;
 
 			/*
 			 * If it's now empty, remove this record.
@@ -6788,7 +6790,8 @@ static int ocfs2_do_truncate(struct ocfs2_super *osb,
 			     struct buffer_head *fe_bh,
 			     handle_t *handle,
 			     struct ocfs2_truncate_context *tc,
-			     struct ocfs2_path *path)
+			     struct ocfs2_path *path,
+			     struct ocfs2_alloc_context *meta_ac)
 {
 	int status;
 	struct ocfs2_dinode *fe;
@@ -6796,6 +6799,7 @@ static int ocfs2_do_truncate(struct ocfs2_super *osb,
 	struct ocfs2_extent_list *el;
 	struct buffer_head *last_eb_bh = NULL;
 	u64 delete_blk = 0;
+	u8 rec_flags;
 
 	fe = (struct ocfs2_dinode *) fe_bh->b_data;
 
@@ -6851,7 +6855,7 @@ static int ocfs2_do_truncate(struct ocfs2_super *osb,
 	inode->i_blocks = ocfs2_inode_sector_count(inode);
 
 	status = ocfs2_trim_tree(inode, path, handle, tc,
-				 clusters_to_del, &delete_blk);
+				 clusters_to_del, &delete_blk, &rec_flags);
 	if (status) {
 		mlog_errno(status);
 		goto bail;
@@ -6883,8 +6887,16 @@ static int ocfs2_do_truncate(struct ocfs2_super *osb,
 	}
 
 	if (delete_blk) {
-		status = ocfs2_truncate_log_append(osb, handle, delete_blk,
-						   clusters_to_del);
+		if (rec_flags & OCFS2_EXT_REFCOUNTED)
+			status = ocfs2_decrease_refcount(inode, fe_bh, handle,
+					ocfs2_blocks_to_clusters(osb->sb,
+								 delete_blk),
+					clusters_to_del, meta_ac,
+					&tc->tc_dealloc);
+		else
+			status = ocfs2_truncate_log_append(osb, handle,
+							   delete_blk,
+							   clusters_to_del);
 		if (status < 0) {
 			mlog_errno(status);
 			goto bail;
@@ -7312,6 +7324,7 @@ int ocfs2_commit_truncate(struct ocfs2_super *osb,
 	struct inode *tl_inode = osb->osb_tl_inode;
 	struct ocfs2_path *path = NULL;
 	struct ocfs2_dinode *di = (struct ocfs2_dinode *)fe_bh->b_data;
+	struct ocfs2_alloc_context *meta_ac = NULL;
 
 	mlog_entry_void();
 
@@ -7337,6 +7350,8 @@ start:
 		goto bail;
 	}
 
+	credits = 0;
+
 	/*
 	 * Truncate always works against the rightmost tree branch.
 	 */
@@ -7389,6 +7404,17 @@ start:
 	mlog(0, "clusters_to_del = %u in this pass, tail blk=%llu\n",
 	     clusters_to_del, (unsigned long long)path_leaf_bh(path)->b_blocknr);
 
+	if (el->l_recs[i].e_flags & OCFS2_EXT_REFCOUNTED) {
+		status = ocfs2_prepare_refcount_change_for_del(inode, fe_bh,
+							       clusters_to_del,
+							       &credits,
+							       &meta_ac);
+		if (status < 0) {
+			mlog_errno(status);
+			goto bail;
+		}
+	}
+
 	mutex_lock(&tl_inode->i_mutex);
 	tl_sem = 1;
 	/* ocfs2_truncate_log_needs_flush guarantees us at least one
@@ -7402,7 +7428,7 @@ start:
 		}
 	}
 
-	credits = ocfs2_calc_tree_trunc_credits(osb->sb, clusters_to_del,
+	credits += ocfs2_calc_tree_trunc_credits(osb->sb, clusters_to_del,
 						(struct ocfs2_dinode *)fe_bh->b_data,
 						el);
 	handle = ocfs2_start_trans(osb, credits);
@@ -7414,7 +7440,7 @@ start:
 	}
 
 	status = ocfs2_do_truncate(osb, clusters_to_del, inode, fe_bh, handle,
-				   tc, path);
+				   tc, path, meta_ac);
 	if (status < 0) {
 		mlog_errno(status);
 		goto bail;
@@ -7428,6 +7454,11 @@ start:
 
 	ocfs2_reinit_path(path, 1);
 
+	if (meta_ac) {
+		ocfs2_free_alloc_context(meta_ac);
+		meta_ac = NULL;
+	}
+
 	/*
 	 * The check above will catch the case where we've truncated
 	 * away all allocation.
@@ -7442,6 +7473,9 @@ bail:
 
 	ocfs2_schedule_truncate_log_flush(osb, 1);
 
+	if (meta_ac)
+		ocfs2_free_alloc_context(meta_ac);
+
 	if (tl_sem)
 		mutex_unlock(&tl_inode->i_mutex);
 
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c
index 73b49cd..403087c 100644
--- a/fs/ocfs2/refcounttree.c
+++ b/fs/ocfs2/refcounttree.c
@@ -717,3 +717,121 @@ static int ocfs2_mark_extent_refcounted(struct inode *inode,
 out:
 	return ret;
 }
+
+/*
+ * Calculate how much credits we need for reflink meta_add blocks.
+ * It is only used when we want to allocate a lot of metas at one time.
+ */
+static int ocfs2_calc_create_meta_credits(struct super_block *sb,
+					  struct ocfs2_extent_tree *et,
+					  int meta_add)
+{
+	int max_sub_alloc = 0, max_group;
+	int bitmap_blocks;
+
+	/*
+	 * calculate the global_bitmap first. It include all the group
+	 * and the dinode and one more group if we relink.
+	 */
+	max_group = meta_add / (OCFS2_SB(sb)->bitmap_cpg * 8) + 1;
+	bitmap_blocks = 1 + max_group * 2;
+
+	/* calculate the local alloc file. */
+	if (OCFS2_SB(sb)->local_alloc_bits)
+		max_sub_alloc = meta_add / OCFS2_SB(sb)->local_alloc_bits + 1;
+
+	mlog(0, "bitmap %d, max_sub %d, meta_add %d\n", bitmap_blocks,
+	     max_sub_alloc, meta_add);
+
+	return bitmap_blocks + max_sub_alloc + meta_add + 1 +
+	       ocfs2_quota_trans_credits(sb);
+}
+
+/*
+ * Calculate if we add len clusters to refcount tree how much meta and credits
+ * we need at most.
+ */
+static int ocfs2_calc_refcount_credits(struct super_block *sb,
+				       struct ocfs2_extent_tree *et,
+				       u32 len, int *meta_add, int *credits)
+{
+	int ret = 0;
+	int recs_per_eb = ocfs2_extent_recs_per_eb(sb);
+	int max_recs_needed = len + 2;
+	int max_eb_needed = max_recs_needed / recs_per_eb + 1;
+	int max_eb_level_2 = max_eb_needed / recs_per_eb + 1;
+	int num_free_extents = ocfs2_num_free_extents(OCFS2_SB(sb), et);
+
+	if (num_free_extents < 0) {
+		ret = num_free_extents;
+		mlog_errno(ret);
+		goto out;
+	}
+
+	*credits += ocfs2_calc_extend_credits(sb,
+					      et->et_root_el,
+					      len);
+
+	if (num_free_extents < max_recs_needed) {
+		*meta_add += ocfs2_extend_meta_needed(et->et_root_el) *
+			     (max_eb_needed + max_eb_level_2);
+
+		*credits += ocfs2_calc_create_meta_credits(sb, et,
+					max_eb_needed + max_eb_level_2);
+	}
+out:
+	return ret;
+}
+
+int ocfs2_prepare_refcount_change_for_del(struct inode *inode,
+					  struct buffer_head *di_bh,
+					  u32 clusters, int *credits,
+					  struct ocfs2_alloc_context **meta_ac)
+{
+	int ret, meta_add = 0;
+	struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+	struct ocfs2_inode_info *oi = OCFS2_I(inode);
+	struct buffer_head *ref_bh = NULL;
+	struct ocfs2_refcount_block *rb;
+	struct ocfs2_extent_tree et;
+
+	if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb))) {
+		ocfs2_error(inode->i_sb, "Inode %lu want to use refcount "
+			    "tree, but the feature bit is not set in the "
+			    "super block.", inode->i_ino);
+		ret = -EROFS;
+		goto out;
+	}
+
+	BUG_ON(!(oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL));
+	BUG_ON(!di->i_refcount_loc);
+
+	ret = ocfs2_read_refcount_block(INODE_CACHE(inode),
+					le64_to_cpu(di->i_refcount_loc),
+					&ref_bh);
+	if (ret < 0) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	rb = (struct ocfs2_refcount_block *)ref_bh->b_data;
+	ocfs2_init_refcount_extent_tree(&et, INODE_CACHE(inode), ref_bh);
+
+	ret = ocfs2_calc_refcount_credits(inode->i_sb, &et, clusters,
+					  &meta_add, credits);
+	if (ret < 0) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	if (meta_add) {
+		ret = ocfs2_reserve_new_metadata_blocks(OCFS2_SB(inode->i_sb),
+							meta_add, meta_ac);
+		if (ret < 0)
+			mlog_errno(ret);
+	}
+
+out:
+	brelse(ref_bh);
+	return ret;
+}
diff --git a/fs/ocfs2/refcounttree.h b/fs/ocfs2/refcounttree.h
index 92fe116..9585a5f 100644
--- a/fs/ocfs2/refcounttree.h
+++ b/fs/ocfs2/refcounttree.h
@@ -27,4 +27,8 @@ int ocfs2_decrease_refcount(struct inode *inode, struct buffer_head *di_bh,
 			    handle_t *handle, u32 cpos, u32 len,
 			    struct ocfs2_alloc_context *meta_ac,
 			    struct ocfs2_cached_dealloc_ctxt *dealloc);
+int ocfs2_prepare_refcount_change_for_del(struct inode *inode,
+					  struct buffer_head *di_bh,
+					  u32 clusters, int *credits,
+					  struct ocfs2_alloc_context **meta_ac);
 #endif /* OCFS2_REFCOUNTTREE_H */
-- 
1.6.2.rc2.16.gf474c




More information about the Ocfs2-devel mailing list