[Cluster-devel] [PATCH 1/3] gfs2: Glock dump improvement (1)

Andreas Gruenbacher agruenba at redhat.com
Mon Dec 18 13:31:20 UTC 2017


Restore an optimization removed in commit 10201655b0 "Fix debugfs glocks
dump": keep the glock hash table iterator active while the glock dump
file is held open.  This avoids having to rescan the hash table from the
start if the user-space buffer the kernel is writing to is sufficiently
small.

This is a partial fix only: if the user-space buffer is roughly as big
as the kernel buffer, the kernel will eventually end up at an entry that
exceeds the kernel-internal buffer (gfs2_glock_seq_show).  The output up
to but excluding that entry will be copied to user-space.  Upon the next
sequential read from user-space, gfs2_glock_seq_start will seek to that
partial entry at the current position, and will continue from there.  At
the moment, this requires scanning the hash table from the start.

Signed-off-by: Andreas Gruenbacher <agruenba at redhat.com>
---
 fs/gfs2/glock.c | 30 +++++++++++++++++++++++-------
 1 file changed, 23 insertions(+), 7 deletions(-)

diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 11066d8647d2..93c7cd2325b4 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -1944,18 +1944,29 @@ static void *gfs2_glock_seq_start(struct seq_file *seq, loff_t *pos)
 	__acquires(RCU)
 {
 	struct gfs2_glock_iter *gi = seq->private;
-	loff_t n = *pos;
+	loff_t n;
+
+	/*
+	 * From the current position, we can either skip to the next hash table
+	 * entry or start from the beginning.
+	 */
+	if (*pos <= gi->last_pos) {
+		rhashtable_walk_exit(&gi->hti);
+		rhashtable_walk_enter(&gl_hash_table, &gi->hti);
+		n = *pos + 1;
+	} else
+		n = *pos - gi->last_pos;
 
-	rhashtable_walk_enter(&gl_hash_table, &gi->hti);
 	if (rhashtable_walk_start(&gi->hti) != 0)
 		return NULL;
 
-	do {
+	while (n--) {
 		gfs2_glock_iter_next(gi);
-	} while (gi->gl && n--);
+		if (!gi->gl)
+			break;
+	}
 
 	gi->last_pos = *pos;
-
 	return gi->gl;
 }
 
@@ -1967,7 +1978,6 @@ static void *gfs2_glock_seq_next(struct seq_file *seq, void *iter_ptr,
 	(*pos)++;
 	gi->last_pos = *pos;
 	gfs2_glock_iter_next(gi);
-
 	return gi->gl;
 }
 
@@ -1978,7 +1988,6 @@ static void gfs2_glock_seq_stop(struct seq_file *seq, void *iter_ptr)
 
 	gi->gl = NULL;
 	rhashtable_walk_stop(&gi->hti);
-	rhashtable_walk_exit(&gi->hti);
 }
 
 static int gfs2_glock_seq_show(struct seq_file *seq, void *iter_ptr)
@@ -2041,10 +2050,16 @@ static int __gfs2_glocks_open(struct inode *inode, struct file *file,
 		struct gfs2_glock_iter *gi = seq->private;
 
 		gi->sdp = inode->i_private;
+		/*
+		 * Initially, we are "before" the first hash table entry; the
+		 * first call to rhashtable_walk_next gets us the first entry.
+		 */
+		gi->last_pos = -1;
 		seq->buf = kmalloc(GFS2_SEQ_GOODSIZE, GFP_KERNEL | __GFP_NOWARN);
 		if (seq->buf)
 			seq->size = GFS2_SEQ_GOODSIZE;
 		gi->gl = NULL;
+		rhashtable_walk_enter(&gl_hash_table, &gi->hti);
 	}
 	return ret;
 }
@@ -2060,6 +2075,7 @@ static int gfs2_glocks_release(struct inode *inode, struct file *file)
 	struct gfs2_glock_iter *gi = seq->private;
 
 	gi->gl = NULL;
+	rhashtable_walk_exit(&gi->hti);
 	return seq_release_private(inode, file);
 }
 
-- 
2.14.3




More information about the Cluster-devel mailing list