[Ocfs2-devel] [PATCH 26/42] ocfs2: lock refcount tree if needed.

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


Signed-off-by: Tao Ma <tao.ma at oracle.com>
---
 fs/ocfs2/alloc.c        |   17 ++++++++++-
 fs/ocfs2/refcounttree.c |   71 +++++++++++++++++++++++++++++------------------
 2 files changed, 60 insertions(+), 28 deletions(-)

diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c
index 8424170..1336ede 100644
--- a/fs/ocfs2/alloc.c
+++ b/fs/ocfs2/alloc.c
@@ -7332,6 +7332,7 @@ int ocfs2_commit_truncate(struct ocfs2_super *osb,
 	struct ocfs2_path *path = NULL;
 	struct ocfs2_dinode *di = (struct ocfs2_dinode *)fe_bh->b_data;
 	struct ocfs2_alloc_context *meta_ac = NULL;
+	struct ocfs2_refcount_tree *ref_tree = NULL;
 
 	mlog_entry_void();
 
@@ -7343,11 +7344,21 @@ int ocfs2_commit_truncate(struct ocfs2_super *osb,
 	if (!path) {
 		status = -ENOMEM;
 		mlog_errno(status);
-		goto bail;
+		goto free;
 	}
 
 	ocfs2_extent_map_trunc(inode, new_highest_cpos);
 
+	if (OCFS2_I(inode)->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL) {
+		status = ocfs2_lock_refcount_tree(osb,
+						le64_to_cpu(di->i_refcount_loc),
+						1, &ref_tree, NULL);
+		if (status) {
+			mlog_errno(status);
+			goto free;
+		}
+	}
+
 start:
 	/*
 	 * Check that we still have allocation to delete.
@@ -7473,6 +7484,9 @@ start:
 	goto start;
 
 bail:
+	if (ref_tree)
+		ocfs2_unlock_refcount_tree(osb, ref_tree, 1);
+
 	if (!status && OCFS2_I(inode)->ip_clusters == 0) {
 		/* remove the refcount tree. */
 		status = ocfs2_remove_refcount_tree(inode, fe_bh);
@@ -7491,6 +7505,7 @@ bail:
 
 	ocfs2_run_deallocs(osb, &tc->tc_dealloc);
 
+free:
 	ocfs2_free_path(path);
 
 	/* This will drop the ext_alloc cluster lock for us */
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c
index d6a6352..cefef7e 100644
--- a/fs/ocfs2/refcounttree.c
+++ b/fs/ocfs2/refcounttree.c
@@ -52,6 +52,9 @@ struct ocfs2_cow_context {
 	u32 cow_len;
 };
 
+static void ocfs2_delete_refcount_tree(struct ocfs2_super *osb,
+				       struct ocfs2_refcount_tree *tree);
+
 static int ocfs2_validate_refcount_block(struct super_block *sb,
 					 struct buffer_head *bh)
 {
@@ -228,15 +231,16 @@ int ocfs2_set_refcount_tree(struct inode *inode,
 	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 	struct buffer_head *ref_bh = NULL;
 	struct ocfs2_refcount_block *rb;
+	struct ocfs2_refcount_tree *ref_tree;
 
 	BUG_ON(oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL);
 	BUG_ON(di->i_refcount_loc);
 
-	ret = ocfs2_read_refcount_block(INODE_CACHE(inode),
-					refcount_loc, &ref_bh);
+	ret = ocfs2_lock_refcount_tree(osb, refcount_loc, 1,
+				       &ref_tree, &ref_bh);
 	if (ret) {
 		mlog_errno(ret);
-		goto out;
+		return ret;
 	}
 
 	handle = ocfs2_start_trans(osb, OCFS2_REFCOUNT_TREE_SET_CREDITS);
@@ -271,9 +275,11 @@ int ocfs2_set_refcount_tree(struct inode *inode,
 	di->i_refcount_loc = cpu_to_le64(refcount_loc);
 	spin_unlock(&oi->ip_lock);
 	ocfs2_journal_dirty(handle, di_bh);
+
 out_commit:
 	ocfs2_commit_trans(osb, handle);
 out:
+	ocfs2_unlock_refcount_tree(osb, ref_tree, 1);
 	brelse(ref_bh);
 
 	return ret;
@@ -281,7 +287,7 @@ out:
 
 int ocfs2_remove_refcount_tree(struct inode *inode, struct buffer_head *di_bh)
 {
-	int ret;
+	int ret, delete_tree = 0;
 	handle_t *handle = NULL;
 	struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
 	struct ocfs2_inode_info *oi = OCFS2_I(inode);
@@ -290,19 +296,19 @@ int ocfs2_remove_refcount_tree(struct inode *inode, struct buffer_head *di_bh)
 	struct inode *alloc_inode = NULL;
 	struct buffer_head *alloc_bh = NULL;
 	struct buffer_head *blk_bh = NULL;
+	struct ocfs2_refcount_tree *ref_tree;
 	int credits = OCFS2_INODE_UPDATE_CREDITS + 1;
-	u64 blk = 0, bg_blkno = 0;
+	u64 blk = 0, bg_blkno = 0, ref_blkno = le64_to_cpu(di->i_refcount_loc);
 	u16 bit = 0;
 
 	if (!(oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL))
 		return 0;
 
-	ret = ocfs2_read_refcount_block(INODE_CACHE(inode),
-					le64_to_cpu(di->i_refcount_loc),
-					&blk_bh);
+	BUG_ON(!ref_blkno);
+	ret = ocfs2_lock_refcount_tree(osb, ref_blkno, 1, &ref_tree, &blk_bh);
 	if (ret) {
 		mlog_errno(ret);
-		goto out;
+		return ret;
 	}
 
 	rb = (struct ocfs2_refcount_block *)blk_bh->b_data;
@@ -367,6 +373,7 @@ int ocfs2_remove_refcount_tree(struct inode *inode, struct buffer_head *di_bh)
 	ocfs2_journal_dirty(handle, blk_bh);
 
 	if (!rb->rf_count) {
+		delete_tree = 1;
 		ret = ocfs2_free_suballoc_bits(handle, alloc_inode,
 					       alloc_bh, bit, bg_blkno, 1);
 		if (ret)
@@ -386,6 +393,9 @@ out_mutex:
 		iput(alloc_inode);
 	}
 out:
+	ocfs2_unlock_refcount_tree(osb, ref_tree, 1);
+	if (delete_tree)
+		ocfs2_delete_refcount_tree(osb, ref_tree);
 	brelse(blk_bh);
 
 	return ret;
@@ -1502,9 +1512,11 @@ int ocfs2_refcount_cow(struct inode *inode,
 	int ret, num_recs = 0, has_data = 0, num_pages = 0;
 	u32 cow_start = 0, cow_len = 0;
 	struct ocfs2_inode_info *oi = OCFS2_I(inode);
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 	struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
 	struct buffer_head *ref_bh = NULL;
 	struct page **pages = NULL;
+	struct ocfs2_refcount_tree *ref_tree;
 	loff_t start, end;
 
 	BUG_ON(!(oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL));
@@ -1515,7 +1527,7 @@ int ocfs2_refcount_cow(struct inode *inode,
 					       &num_recs, &has_data);
 	if (ret) {
 		mlog_errno(ret);
-		goto out;
+		return ret;
 	}
 	mlog(0, "CoW inode %lu, cpos %u, write_len %u, cow_start %u, "
 	     "cow_len %u, num_recs %d\n", inode->i_ino,
@@ -1542,10 +1554,9 @@ int ocfs2_refcount_cow(struct inode *inode,
 		}
 	}
 
-	ret = ocfs2_read_refcount_block(INODE_CACHE(inode),
-					le64_to_cpu(di->i_refcount_loc),
-					&ref_bh);
-	if (ret < 0) {
+	ret = ocfs2_lock_refcount_tree(osb, le64_to_cpu(di->i_refcount_loc),
+				       1, &ref_tree, &ref_bh);
+	if (ret) {
 		mlog_errno(ret);
 		goto out;
 	}
@@ -1556,12 +1567,13 @@ int ocfs2_refcount_cow(struct inode *inode,
 	if (ret)
 		mlog_errno(ret);
 
+	ocfs2_unlock_refcount_tree(osb, ref_tree, 1);
+	brelse(ref_bh);
 out:
 	if (pages) {
 		ocfs2_unlock_and_free_pages(pages, num_pages);
 		kfree(pages);
 	}
-	brelse(ref_bh);
 	return ret;
 }
 
@@ -1626,6 +1638,8 @@ static int ocfs2_attach_refcount_tree(struct inode *inode,
 	struct buffer_head *ref_bh = NULL;
 	struct ocfs2_inode_info *oi = OCFS2_I(inode);
 	struct ocfs2_dinode *di = (struct ocfs2_dinode *)fe_bh->b_data;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+	struct ocfs2_refcount_tree *ref_tree;
 	unsigned int ext_flags;
 	loff_t size;
 	u32 cpos, num_clusters, clusters, p_cluster;
@@ -1644,9 +1658,9 @@ static int ocfs2_attach_refcount_tree(struct inode *inode,
 	}
 
 	BUG_ON(!di->i_refcount_loc);
-	ret = ocfs2_read_refcount_block(INODE_CACHE(inode),
-					le64_to_cpu(di->i_refcount_loc),
-					&ref_bh);
+	ret = ocfs2_lock_refcount_tree(osb,
+				       le64_to_cpu(di->i_refcount_loc), 1,
+				       &ref_tree, &ref_bh);
 	if (ret) {
 		mlog_errno(ret);
 		goto out;
@@ -1682,13 +1696,15 @@ static int ocfs2_attach_refcount_tree(struct inode *inode,
 	 * record from the disk.
 	 */
 	ocfs2_extent_map_trunc(inode, 0);
+
+	ocfs2_unlock_refcount_tree(osb, ref_tree, 1);
 	brelse(ref_bh);
-out:
 
 	if (!ret && ocfs2_dealloc_has_cluster(&dealloc)) {
-		ocfs2_schedule_truncate_log_flush(OCFS2_SB(inode->i_sb), 1);
-		ocfs2_run_deallocs(OCFS2_SB(inode->i_sb), &dealloc);
+		ocfs2_schedule_truncate_log_flush(osb, 1);
+		ocfs2_run_deallocs(osb, &dealloc);
 	}
+out:
 	return ret;
 }
 
@@ -1780,6 +1796,7 @@ static int ocfs2_create_reflink_node(struct inode *s_inode,
 	struct ocfs2_super *osb = OCFS2_SB(s_inode->i_sb);
 	struct ocfs2_refcount_block *rb;
 	struct ocfs2_dinode *di = (struct ocfs2_dinode *)s_bh->b_data;
+	struct ocfs2_refcount_tree *ref_tree;
 	struct ocfs2_extent_list *el;
 	struct ocfs2_extent_tree ref_et;
 
@@ -1792,9 +1809,8 @@ static int ocfs2_create_reflink_node(struct inode *s_inode,
 		goto out;
 	}
 
-	ret = ocfs2_read_refcount_block(INODE_CACHE(t_inode),
-					le64_to_cpu(di->i_refcount_loc),
-					&ref_bh);
+	ret = ocfs2_lock_refcount_tree(osb, le64_to_cpu(di->i_refcount_loc),
+				       1, &ref_tree, &ref_bh);
 	if (ret) {
 		mlog_errno(ret);
 		goto out;
@@ -1825,7 +1841,7 @@ static int ocfs2_create_reflink_node(struct inode *s_inode,
 							meta_add, &meta_ac);
 		if (ret) {
 			mlog_errno(ret);
-			goto out;
+			goto out_unlock_refcount;
 		}
 	}
 
@@ -1846,14 +1862,15 @@ static int ocfs2_create_reflink_node(struct inode *s_inode,
 out_free_resource:
 	if (meta_ac)
 		ocfs2_free_alloc_context(meta_ac);
+out_unlock_refcount:
+	ocfs2_unlock_refcount_tree(osb, ref_tree, 1);
+	brelse(ref_bh);
 out:
 	if (ocfs2_dealloc_has_cluster(&dealloc)) {
 		ocfs2_schedule_truncate_log_flush(osb, 1);
 		ocfs2_run_deallocs(osb, &dealloc);
 	}
 
-	brelse(ref_bh);
-
 	return ret;
 }
 
-- 
1.6.2.rc2.16.gf474c




More information about the Ocfs2-devel mailing list