[Ocfs2-devel] [PATCH 14/42] ocfs2: Add support of decrementing refcount for delete.

Tao Ma tao.ma at oracle.com
Thu Apr 2 16:45:53 PDT 2009


    Given a physical cpos and length, decrement the refcount
in the tree. If the refcount for any portion of the extent goes
to zero, that portion is queued for freeing.

Signed-off-by: Tao Ma <tao.ma at oracle.com>
---
 fs/ocfs2/refcounttree.c |  115 +++++++++++++++++++++++++++++++++++++++++++++++
 fs/ocfs2/refcounttree.h |    4 ++
 2 files changed, 119 insertions(+), 0 deletions(-)

diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c
index 3b6f327..6b42ce8 100644
--- a/fs/ocfs2/refcounttree.c
+++ b/fs/ocfs2/refcounttree.c
@@ -563,3 +563,118 @@ out:
 	ocfs2_free_path(path);
 	return ret;
 }
+
+static int __ocfs2_decrease_refcount(handle_t *handle,
+				     struct ocfs2_extent_tree *et,
+				     u32 cpos, u32 len,
+				     struct ocfs2_alloc_context *meta_ac,
+				     struct ocfs2_cached_dealloc_ctxt *dealloc)
+{
+	int ret = 0, index = 0;
+	struct ocfs2_extent_rec rec;
+	unsigned int r_count = 0, r_len;
+	struct ocfs2_path *path = NULL;
+	struct super_block *sb = ocfs2_metadata_cache_get_super(et->et_ci);
+
+	path = ocfs2_new_path_from_et(et);
+	if (!path) {
+		ret = -ENOMEM;
+		mlog_errno(ret);
+		goto out;
+	}
+
+	mlog(0, "Tree owner %llu, decrease refcount start %u, len %u\n",
+	     (unsigned long long)ocfs2_metadata_cache_owner(et->et_ci),
+	     cpos, len);
+
+	while (len) {
+		ret = ocfs2_get_refcount_rec(et->et_ci, path, cpos, len,
+					     &rec, &index);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+
+		r_count = le32_to_cpu(rec.e_refcount);
+		BUG_ON(r_count == 0);
+
+		r_len = min((u32)(cpos + len), le32_to_cpu(rec.e_cpos) +
+			      le16_to_cpu(rec.e_leaf_clusters)) - cpos;
+
+		/*
+		 * Now decrease the refcount:
+		 *
+		 * 1. r_count == 1, remove it from refcount tree and queue
+		 *    clusters for free.
+		 * 2. r_count > 2, split the record.
+		 */
+		if (le32_to_cpu(rec.e_refcount) == 1) {
+			ret = ocfs2_remove_extent(handle, et, cpos, r_len,
+						  meta_ac, dealloc);
+			if (ret) {
+				mlog_errno(ret);
+				goto out;
+			}
+
+			ret = ocfs2_cache_cluster_dealloc(dealloc,
+					  ocfs2_clusters_to_blocks(sb, cpos),
+							  r_len);
+			if (ret) {
+				mlog_errno(ret);
+				goto out;
+			}
+		} else {
+			rec.e_cpos = cpu_to_le32(cpos);
+			rec.e_leaf_clusters = cpu_to_le16(r_len);
+
+			le32_add_cpu(&rec.e_refcount, -1);
+
+			ret = ocfs2_split_extent(handle, et, path, index,
+						 &rec, meta_ac, dealloc);
+			if (ret) {
+				mlog_errno(ret);
+				goto out;
+			}
+		}
+
+		cpos += r_len;
+		len -= r_len;
+		ocfs2_reinit_path(path, 1);
+	}
+
+out:
+	ocfs2_free_path(path);
+	return ret;
+}
+
+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 ret;
+	struct ocfs2_inode_info *oi = OCFS2_I(inode);
+	struct buffer_head *ref_bh = NULL;
+	struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+	struct ocfs2_extent_tree et;
+
+	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) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	ocfs2_init_refcount_extent_tree(&et, INODE_CACHE(inode), ref_bh);
+	ret = __ocfs2_decrease_refcount(handle, &et,
+					cpos, len, meta_ac, dealloc);
+	if (ret)
+		mlog_errno(ret);
+out:
+	brelse(ref_bh);
+	return ret;
+}
diff --git a/fs/ocfs2/refcounttree.h b/fs/ocfs2/refcounttree.h
index 9f4bdac..92fe116 100644
--- a/fs/ocfs2/refcounttree.h
+++ b/fs/ocfs2/refcounttree.h
@@ -23,4 +23,8 @@ int ocfs2_set_refcount_tree(struct inode *inode,
 			    u64 blkno);
 int ocfs2_remove_refcount_tree(struct inode *inode, struct buffer_head *di_bh);
 
+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);
 #endif /* OCFS2_REFCOUNTTREE_H */
-- 
1.6.2.rc2.16.gf474c




More information about the Ocfs2-devel mailing list