[Cluster-devel] [GFS2 PATCH 3/3] GFS2: Reduce contention on gfs2_log_lock

Bob Peterson rpeterso at redhat.com
Wed Jan 25 19:58:50 UTC 2017


This patch reworks some of the log locks to provide less contention.

Signed-off-by: Bob Peterson <rpeterso at redhat.com>
---
 fs/gfs2/aops.c    | 23 ++++++-------------
 fs/gfs2/glops.c   |  4 ++--
 fs/gfs2/log.c     |  6 ++---
 fs/gfs2/lops.c    |  3 ++-
 fs/gfs2/meta_io.c | 11 +++++----
 fs/gfs2/trans.c   | 67 +++++++++++++++++++++++++------------------------------
 6 files changed, 51 insertions(+), 63 deletions(-)

diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c
index 5a6f52e..d3cd30d 100644
--- a/fs/gfs2/aops.c
+++ b/fs/gfs2/aops.c
@@ -986,23 +986,13 @@ static sector_t gfs2_bmap(struct address_space *mapping, sector_t lblock)
 
 static void gfs2_discard(struct gfs2_sbd *sdp, struct buffer_head *bh)
 {
-	struct gfs2_bufdata *bd;
-
 	lock_buffer(bh);
-	gfs2_log_lock(sdp);
 	clear_buffer_dirty(bh);
-	bd = bh->b_private;
-	if (bd) {
-		if (!list_empty(&bd->bd_list) && !buffer_pinned(bh))
-			list_del_init(&bd->bd_list);
-		else
-			gfs2_remove_from_journal(bh, REMOVE_JDATA);
-	}
+	gfs2_remove_from_journal(bh, REMOVE_JDATA);
 	bh->b_bdev = NULL;
 	clear_buffer_mapped(bh);
 	clear_buffer_req(bh);
 	clear_buffer_new(bh);
-	gfs2_log_unlock(sdp);
 	unlock_buffer(bh);
 }
 
@@ -1157,7 +1147,6 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask)
 	 * on dirty buffers like we used to here again.
 	 */
 
-	gfs2_log_lock(sdp);
 	spin_lock(&sdp->sd_ail_lock);
 	head = bh = page_buffers(page);
 	do {
@@ -1174,25 +1163,27 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask)
 
 	head = bh = page_buffers(page);
 	do {
+		lock_buffer(bh);
 		bd = bh->b_private;
 		if (bd) {
 			gfs2_assert_warn(sdp, bd->bd_bh == bh);
+			gfs2_log_lock(sdp);
 			if (!list_empty(&bd->bd_list))
 				list_del_init(&bd->bd_list);
+			gfs2_log_unlock(sdp);
 			bd->bd_bh = NULL;
 			bh->b_private = NULL;
-			kmem_cache_free(gfs2_bufdata_cachep, bd);
 		}
-
+		unlock_buffer(bh);
+		if (bd)
+			kmem_cache_free(gfs2_bufdata_cachep, bd);
 		bh = bh->b_this_page;
 	} while (bh != head);
-	gfs2_log_unlock(sdp);
 
 	return try_to_free_buffers(page);
 
 cannot_release:
 	spin_unlock(&sdp->sd_ail_lock);
-	gfs2_log_unlock(sdp);
 	return 0;
 }
 
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index 5db59d4..fced99b 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -61,7 +61,6 @@ static void __gfs2_ail_flush(struct gfs2_glock *gl, bool fsync,
 	struct buffer_head *bh;
 	const unsigned long b_state = (1UL << BH_Dirty)|(1UL << BH_Pinned)|(1UL << BH_Lock);
 
-	gfs2_log_lock(sdp);
 	spin_lock(&sdp->sd_ail_lock);
 	list_for_each_entry_safe_reverse(bd, tmp, head, bd_ail_gl_list) {
 		if (nr_revokes == 0)
@@ -72,12 +71,13 @@ static void __gfs2_ail_flush(struct gfs2_glock *gl, bool fsync,
 				continue;
 			gfs2_ail_error(gl, bh);
 		}
+		gfs2_log_lock(sdp);
 		gfs2_trans_add_revoke(sdp, bd);
+		gfs2_log_unlock(sdp);
 		nr_revokes--;
 	}
 	GLOCK_BUG_ON(gl, !fsync && atomic_read(&gl->gl_ail_count));
 	spin_unlock(&sdp->sd_ail_lock);
-	gfs2_log_unlock(sdp);
 }
 
 
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
index 4fb76c0..4d5f3a1 100644
--- a/fs/gfs2/log.c
+++ b/fs/gfs2/log.c
@@ -624,8 +624,8 @@ done:
 		if (!sdp->sd_log_blks_reserved)
 			atomic_dec(&sdp->sd_log_blks_free);
 	}
-	gfs2_log_lock(sdp);
 	spin_lock(&sdp->sd_ail_lock);
+	gfs2_log_lock(sdp);
 	list_for_each_entry(tr, &sdp->sd_ail1_list, tr_list) {
 		list_for_each_entry_safe(bd, tmp, &tr->tr_ail2_list, bd_ail_st_list) {
 			if (max_revokes == 0)
@@ -637,8 +637,8 @@ done:
 		}
 	}
 out_of_blocks:
-	spin_unlock(&sdp->sd_ail_lock);
 	gfs2_log_unlock(sdp);
+	spin_unlock(&sdp->sd_ail_lock);
 
 	if (!sdp->sd_log_num_revoke) {
 		atomic_inc(&sdp->sd_log_blks_free);
@@ -756,6 +756,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl,
 	sdp->sd_log_head = sdp->sd_log_flush_head;
 	sdp->sd_log_blks_reserved = 0;
 	sdp->sd_log_commited_revoke = 0;
+	gfs2_log_unlock(sdp);
 
 	spin_lock(&sdp->sd_ail_lock);
 	if (tr && !list_empty(&tr->tr_ail1_list)) {
@@ -763,7 +764,6 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl,
 		tr = NULL;
 	}
 	spin_unlock(&sdp->sd_ail_lock);
-	gfs2_log_unlock(sdp);
 
 	if (type != NORMAL_FLUSH) {
 		if (!sdp->sd_log_idle) {
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
index 49d5a1b..d6a3bdb 100644
--- a/fs/gfs2/lops.c
+++ b/fs/gfs2/lops.c
@@ -98,12 +98,13 @@ static void maybe_release_space(struct gfs2_bufdata *bd)
 static void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
 		       struct gfs2_trans *tr)
 {
-	struct gfs2_bufdata *bd = bh->b_private;
+	struct gfs2_bufdata *bd;
 
 	BUG_ON(!buffer_uptodate(bh));
 	BUG_ON(!buffer_pinned(bh));
 
 	lock_buffer(bh);
+	bd = bh->b_private;
 	mark_buffer_dirty(bh);
 	clear_buffer_pinned(bh);
 
diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c
index a88a347..d870b15 100644
--- a/fs/gfs2/meta_io.c
+++ b/fs/gfs2/meta_io.c
@@ -341,18 +341,24 @@ void gfs2_remove_from_journal(struct buffer_head *bh, int meta)
 	if (test_clear_buffer_pinned(bh)) {
 		trace_gfs2_pin(bd, 0);
 		atomic_dec(&sdp->sd_log_pinned);
+		gfs2_log_lock(sdp);
 		list_del_init(&bd->bd_list);
 		if (meta == REMOVE_META)
 			tr->tr_num_buf_rm++;
 		else
 			tr->tr_num_databuf_rm++;
 		set_bit(TR_TOUCHED, &tr->tr_flags);
+		gfs2_log_unlock(sdp);
 		was_pinned = 1;
 		brelse(bh);
 	}
 	if (bd) {
 		spin_lock(&sdp->sd_ail_lock);
-		if (bd->bd_tr) {
+		if (!meta && !was_pinned && !list_empty(&bd->bd_list)) {
+			gfs2_log_lock(sdp);
+			list_del_init(&bd->bd_list);
+			gfs2_log_unlock(sdp);
+		} else if (bd->bd_tr) {
 			gfs2_trans_add_revoke(sdp, bd);
 		} else if (was_pinned) {
 			bh->b_private = NULL;
@@ -374,16 +380,13 @@ void gfs2_remove_from_journal(struct buffer_head *bh, int meta)
 
 void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen)
 {
-	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
 	struct buffer_head *bh;
 
 	while (blen) {
 		bh = gfs2_getbuf(ip->i_gl, bstart, NO_CREATE);
 		if (bh) {
 			lock_buffer(bh);
-			gfs2_log_lock(sdp);
 			gfs2_remove_from_journal(bh, REMOVE_META);
-			gfs2_log_unlock(sdp);
 			unlock_buffer(bh);
 			brelse(bh);
 		}
diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c
index 483c5a7..f7addc5 100644
--- a/fs/gfs2/trans.c
+++ b/fs/gfs2/trans.c
@@ -123,18 +123,37 @@ void gfs2_trans_end(struct gfs2_sbd *sdp)
 		sb_end_intwrite(sdp->sd_vfs);
 }
 
-static struct gfs2_bufdata *gfs2_alloc_bufdata(struct gfs2_glock *gl,
-					       struct buffer_head *bh,
-					       const struct gfs2_log_operations *lops)
+/* lock_bh_get_bd - lock buffer_head and return its bd
+ *
+ * This function locks the buffer_head and returns its bd.
+ * If there's no bd, a new one is created, protected by the bh lock.
+ */
+static struct gfs2_bufdata *lock_bh_get_bd(struct gfs2_glock *gl,
+					   struct buffer_head *bh,
+					   const struct gfs2_log_operations *lops)
 {
 	struct gfs2_bufdata *bd;
 
+	lock_buffer(bh);
+	bd = bh->b_private;
+	if (bd)
+		goto out;
+
+	unlock_buffer(bh);
 	bd = kmem_cache_zalloc(gfs2_bufdata_cachep, GFP_NOFS | __GFP_NOFAIL);
 	bd->bd_bh = bh;
 	bd->bd_gl = gl;
 	bd->bd_ops = lops;
 	INIT_LIST_HEAD(&bd->bd_list);
+	lock_buffer(bh);
+	if (bh->b_private) { /* someone prempted us */
+		kmem_cache_free(gfs2_bufdata_cachep, bd);
+		bd = bh->b_private;
+		goto out;
+	}
+	gfs2_assert(gl->gl_name.ln_sbd, bd->bd_gl == gl);
 	bh->b_private = bd;
+out:
 	return bd;
 }
 
@@ -169,29 +188,17 @@ void gfs2_trans_add_data(struct gfs2_glock *gl, struct buffer_head *bh)
 		return;
 	}
 
-	lock_buffer(bh);
-	gfs2_log_lock(sdp);
-	bd = bh->b_private;
-	if (bd == NULL) {
-		gfs2_log_unlock(sdp);
-		unlock_buffer(bh);
-		if (bh->b_private == NULL)
-			bd = gfs2_alloc_bufdata(gl, bh, &gfs2_databuf_lops);
-		else
-			bd = bh->b_private;
-		lock_buffer(bh);
-		gfs2_log_lock(sdp);
-	}
-	gfs2_assert(sdp, bd->bd_gl == gl);
+	bd = lock_bh_get_bd(gl, bh, &gfs2_databuf_lops);
 	set_bit(TR_TOUCHED, &tr->tr_flags);
 	if (list_empty(&bd->bd_list)) {
+		gfs2_pin(sdp, bd->bd_bh);
 		set_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags);
 		set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags);
-		gfs2_pin(sdp, bd->bd_bh);
 		tr->tr_num_databuf_new++;
+		gfs2_log_lock(sdp);
 		list_add_tail(&bd->bd_list, &tr->tr_databuf);
+		gfs2_log_unlock(sdp);
 	}
-	gfs2_log_unlock(sdp);
 	unlock_buffer(bh);
 }
 
@@ -204,26 +211,12 @@ void gfs2_trans_add_meta(struct gfs2_glock *gl, struct buffer_head *bh)
 	struct gfs2_trans *tr;
 	enum gfs2_freeze_state state = atomic_read(&sdp->sd_freeze_state);
 
-	lock_buffer(bh);
-	gfs2_log_lock(sdp);
-	bd = bh->b_private;
-	if (bd == NULL) {
-		gfs2_log_unlock(sdp);
-		unlock_buffer(bh);
-		lock_page(bh->b_page);
-		if (bh->b_private == NULL)
-			bd = gfs2_alloc_bufdata(gl, bh, &gfs2_buf_lops);
-		else
-			bd = bh->b_private;
-		unlock_page(bh->b_page);
-		lock_buffer(bh);
-		gfs2_log_lock(sdp);
-	}
-	gfs2_assert(sdp, bd->bd_gl == gl);
+	bd = lock_bh_get_bd(gl, bh, &gfs2_buf_lops);
 	tr = current->journal_info;
 	set_bit(TR_TOUCHED, &tr->tr_flags);
 	if (!list_empty(&bd->bd_list))
 		goto out_unlock;
+	gfs2_pin(sdp, bd->bd_bh);
 	set_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags);
 	set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags);
 	mh = (struct gfs2_meta_header *)bd->bd_bh->b_data;
@@ -236,13 +229,13 @@ void gfs2_trans_add_meta(struct gfs2_glock *gl, struct buffer_head *bh)
 		printk(KERN_INFO "GFS2:adding buf while frozen\n");
 		gfs2_assert_withdraw(sdp, 0);
 	}
-	gfs2_pin(sdp, bd->bd_bh);
 	mh->__pad0 = cpu_to_be64(0);
 	mh->mh_jid = cpu_to_be32(sdp->sd_jdesc->jd_jid);
+	gfs2_log_lock(sdp);
 	list_add(&bd->bd_list, &tr->tr_buf);
+	gfs2_log_unlock(sdp);
 	tr->tr_num_buf_new++;
 out_unlock:
-	gfs2_log_unlock(sdp);
 	unlock_buffer(bh);
 }
 
-- 
2.9.3




More information about the Cluster-devel mailing list