[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[Cluster-devel] [PATCH 4/4] gfs2: introduce AIL lock



THe log lock is currently used to protect the AIL lists and
the movements of buffers into and out of them. The lists
are self contained and no log specific items outside the
lists are accessed when starting or emptying the AIL lists.

Hence the operation of the AIL does not require the protection
of the log lock so split them out into a new AIL specific lock
to reduce the amount of traffic on the log lock. This will
also reduce the amount of serialisation that occurs when
the gfs2_logd pushes on the AIL to move it forward.

This reduces the impact of log pushing on sequential write
throughput. On no-op scheduler on a disk that can do 85MB/s,
this increases the write rate from 65MB/s with the ordering
fixes to 75MB/s.

Signed-off-by: Dave Chinner <dchinner redhat com>
---
 fs/gfs2/glops.c      |   10 ++++++++--
 fs/gfs2/incore.h     |    1 +
 fs/gfs2/log.c        |   32 +++++++++++++++++---------------
 fs/gfs2/log.h        |   22 ++++++++++++++++++++++
 fs/gfs2/lops.c       |    5 ++++-
 fs/gfs2/ops_fstype.c |    1 +
 6 files changed, 53 insertions(+), 18 deletions(-)

diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index 78554ac..65048f9 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -57,20 +57,26 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl)
 	BUG_ON(current->journal_info);
 	current->journal_info = &tr;
 
-	gfs2_log_lock(sdp);
+	gfs2_ail_lock(sdp);
 	while (!list_empty(head)) {
 		bd = list_entry(head->next, struct gfs2_bufdata,
 				bd_ail_gl_list);
 		bh = bd->bd_bh;
 		gfs2_remove_from_ail(bd);
+		gfs2_ail_unlock(sdp);
+
 		bd->bd_bh = NULL;
 		bh->b_private = NULL;
 		bd->bd_blkno = bh->b_blocknr;
+		gfs2_log_lock(sdp);
 		gfs2_assert_withdraw(sdp, !buffer_busy(bh));
 		gfs2_trans_add_revoke(sdp, bd);
+		gfs2_log_unlock(sdp);
+
+		gfs2_ail_lock(sdp);
 	}
 	gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count));
-	gfs2_log_unlock(sdp);
+	gfs2_ail_unlock(sdp);
 
 	gfs2_trans_end(sdp);
 	gfs2_log_flush(sdp, NULL);
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index 4792200..00d610f 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -644,6 +644,7 @@ struct gfs2_sbd {
 	unsigned int sd_log_flush_head;
 	u64 sd_log_flush_wrapped;
 
+	spinlock_t sd_ail_lock;
 	struct list_head sd_ail1_list;
 	struct list_head sd_ail2_list;
 	u64 sd_ail_sync_gen;
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
index a9797be..f2ee615 100644
--- a/fs/gfs2/log.c
+++ b/fs/gfs2/log.c
@@ -89,8 +89,8 @@ void gfs2_remove_from_ail(struct gfs2_bufdata *bd)
  */
 
 static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
-__releases(&sdp->sd_log_lock)
-__acquires(&sdp->sd_log_lock)
+__releases(&sdp->sd_ail_lock)
+__acquires(&sdp->sd_ail_lock)
 {
 	struct gfs2_bufdata *bd, *s;
 	struct buffer_head *bh;
@@ -118,7 +118,7 @@ __acquires(&sdp->sd_log_lock)
 			list_move(&bd->bd_ail_st_list, &ai->ai_ail1_list);
 
 			get_bh(bh);
-			gfs2_log_unlock(sdp);
+			gfs2_ail_unlock(sdp);
 			lock_buffer(bh);
 			if (test_clear_buffer_dirty(bh)) {
 				bh->b_end_io = end_buffer_write_sync;
@@ -128,7 +128,7 @@ __acquires(&sdp->sd_log_lock)
 				unlock_buffer(bh);
 				brelse(bh);
 			}
-			gfs2_log_lock(sdp);
+			gfs2_ail_lock(sdp);
 
 			retry = 1;
 			break;
@@ -178,10 +178,10 @@ static void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags)
 	struct gfs2_ail *first_ai, *ai, *tmp;
 	int done = 0;
 
-	gfs2_log_lock(sdp);
+	gfs2_ail_lock(sdp);
 	head = &sdp->sd_ail1_list;
 	if (list_empty(head)) {
-		gfs2_log_unlock(sdp);
+		gfs2_ail_unlock(sdp);
 		return;
 	}
 	sync_gen = sdp->sd_ail_sync_gen++;
@@ -189,7 +189,7 @@ static void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags)
 	first = head->prev;
 	first_ai = list_entry(first, struct gfs2_ail, ai_list);
 	first_ai->ai_sync_gen = sync_gen;
-	gfs2_ail1_start_one(sdp, first_ai); /* This may drop log lock */
+	gfs2_ail1_start_one(sdp, first_ai); /* This may drop ail lock */
 
 	if (flags & DIO_ALL)
 		first = NULL;
@@ -204,13 +204,13 @@ static void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags)
 			if (ai->ai_sync_gen >= sync_gen)
 				continue;
 			ai->ai_sync_gen = sync_gen;
-			gfs2_ail1_start_one(sdp, ai); /* This may drop log lock */
+			gfs2_ail1_start_one(sdp, ai); /* This may drop ail lock */
 			done = 0;
 			break;
 		}
 	}
 
-	gfs2_log_unlock(sdp);
+	gfs2_ail_unlock(sdp);
 }
 
 static int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags)
@@ -218,7 +218,7 @@ static int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags)
 	struct gfs2_ail *ai, *s;
 	int ret;
 
-	gfs2_log_lock(sdp);
+	gfs2_ail_lock(sdp);
 
 	list_for_each_entry_safe_reverse(ai, s, &sdp->sd_ail1_list, ai_list) {
 		if (gfs2_ail1_empty_one(sdp, ai, flags))
@@ -229,7 +229,7 @@ static int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags)
 
 	ret = list_empty(&sdp->sd_ail1_list);
 
-	gfs2_log_unlock(sdp);
+	gfs2_ail_unlock(sdp);
 
 	return ret;
 }
@@ -262,7 +262,7 @@ static void ail2_empty(struct gfs2_sbd *sdp, unsigned int new_tail)
 	int wrap = (new_tail < old_tail);
 	int a, b, rm;
 
-	gfs2_log_lock(sdp);
+	gfs2_ail_lock(sdp);
 
 	list_for_each_entry_safe(ai, safe, &sdp->sd_ail2_list, ai_list) {
 		a = (old_tail <= ai->ai_first);
@@ -278,7 +278,7 @@ static void ail2_empty(struct gfs2_sbd *sdp, unsigned int new_tail)
 		kfree(ai);
 	}
 
-	gfs2_log_unlock(sdp);
+	gfs2_ail_unlock(sdp);
 }
 
 /**
@@ -437,7 +437,7 @@ static unsigned int current_tail(struct gfs2_sbd *sdp)
 	struct gfs2_ail *ai;
 	unsigned int tail;
 
-	gfs2_log_lock(sdp);
+	gfs2_ail_lock(sdp);
 
 	if (list_empty(&sdp->sd_ail1_list)) {
 		tail = sdp->sd_log_head;
@@ -446,7 +446,7 @@ static unsigned int current_tail(struct gfs2_sbd *sdp)
 		tail = ai->ai_first;
 	}
 
-	gfs2_log_unlock(sdp);
+	gfs2_ail_unlock(sdp);
 
 	return tail;
 }
@@ -775,10 +775,12 @@ void __gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
 	sdp->sd_log_commited_databuf = 0;
 	sdp->sd_log_commited_revoke = 0;
 
+	gfs2_ail_lock(sdp);
 	if (!list_empty(&ai->ai_ail1_list)) {
 		list_add(&ai->ai_list, &sdp->sd_ail1_list);
 		ai = NULL;
 	}
+	gfs2_ail_unlock(sdp);
 	gfs2_log_unlock(sdp);
 	trace_gfs2_log_flush(sdp, 0);
 	up_write(&sdp->sd_log_flush_lock);
diff --git a/fs/gfs2/log.h b/fs/gfs2/log.h
index 7c64510..62c110e 100644
--- a/fs/gfs2/log.h
+++ b/fs/gfs2/log.h
@@ -38,6 +38,28 @@ __releases(&sdp->sd_log_lock)
 	spin_unlock(&sdp->sd_log_lock);
 }
 
+/**
+ * gfs2_ail_lock - acquire the right to mess with the AIL
+ * @sdp: the filesystem
+ *
+ */
+static inline void gfs2_ail_lock(struct gfs2_sbd *sdp)
+__acquires(&sdp->sd_ail_lock)
+{
+	spin_lock(&sdp->sd_ail_lock);
+}
+
+/**
+ * gfs2_ail_unlock - release the right to mess with the AIL
+ * @sdp: the filesystem
+ *
+ */
+static inline void gfs2_ail_unlock(struct gfs2_sbd *sdp)
+__releases(&sdp->sd_ail_lock)
+{
+	spin_unlock(&sdp->sd_ail_lock);
+}
+
 static inline void gfs2_log_pointers_init(struct gfs2_sbd *sdp,
 					  unsigned int value)
 {
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
index 0fe2f3c..342d65e 100644
--- a/fs/gfs2/lops.c
+++ b/fs/gfs2/lops.c
@@ -80,7 +80,7 @@ static void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
 	mark_buffer_dirty(bh);
 	clear_buffer_pinned(bh);
 
-	gfs2_log_lock(sdp);
+	gfs2_ail_lock(sdp);
 	if (bd->bd_ail) {
 		list_del(&bd->bd_ail_st_list);
 		brelse(bh);
@@ -91,6 +91,9 @@ static void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
 	}
 	bd->bd_ail = ai;
 	list_add(&bd->bd_ail_st_list, &ai->ai_ail1_list);
+	gfs2_ail_unlock(sdp);
+
+	gfs2_log_lock(sdp);
 	clear_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags);
 	trace_gfs2_pin(bd, 0);
 	gfs2_log_unlock(sdp);
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index edfee24..14ecb2b 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -108,6 +108,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
 	INIT_LIST_HEAD(&sdp->sd_log_le_ordered);
 
 	mutex_init(&sdp->sd_log_reserve_mutex);
+	spin_lock_init(&sdp->sd_ail_lock);
 	INIT_LIST_HEAD(&sdp->sd_ail1_list);
 	INIT_LIST_HEAD(&sdp->sd_ail2_list);
 
-- 
1.6.5


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]