aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruenba@redhat.com>2018-01-08 16:35:43 -0500
committerBob Peterson <rpeterso@redhat.com>2018-02-01 13:27:11 -0500
commit7ac07fdaf840f9b141c6d5c286805107227c0e68 (patch)
treeedfefcd997343e552b05fed68cd2f439dd55ae54
parentdcb2cd55cf43fe06ada66265c1e088a4b08d3e3d (diff)
gfs2: Glock dump performance regression fix
Restore an optimization removed in commit 7f19449553 "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 for each read, with quadratically rising runtime. In addition, use rhastable_walk_peek for resuming a glock dump at the current position: when a glock doesn't fit in the provided buffer anymore, the next read must revisit the same glock. Finally, also restart the dump from the first entry when we notice that the hash table has been resized in gfs2_glock_seq_start. Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com> Signed-off-by: Bob Peterson <rpeterso@redhat.com>
-rw-r--r--fs/gfs2/glock.c65
1 files changed, 43 insertions, 22 deletions
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 90af87ff29ba..82fb5583445c 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -1921,19 +1921,29 @@ void gfs2_glock_exit(void)
1921 destroy_workqueue(gfs2_delete_workqueue); 1921 destroy_workqueue(gfs2_delete_workqueue);
1922} 1922}
1923 1923
1924static void gfs2_glock_iter_next(struct gfs2_glock_iter *gi) 1924static void gfs2_glock_iter_next(struct gfs2_glock_iter *gi, loff_t n)
1925{ 1925{
1926 while ((gi->gl = rhashtable_walk_next(&gi->hti))) { 1926 if (n == 0)
1927 if (IS_ERR(gi->gl)) { 1927 gi->gl = rhashtable_walk_peek(&gi->hti);
1928 if (PTR_ERR(gi->gl) == -EAGAIN) 1928 else {
1929 continue; 1929 gi->gl = rhashtable_walk_next(&gi->hti);
1930 gi->gl = NULL; 1930 n--;
1931 return; 1931 }
1932 for (;;) {
1933 if (IS_ERR_OR_NULL(gi->gl)) {
1934 if (!gi->gl)
1935 return;
1936 if (PTR_ERR(gi->gl) != -EAGAIN) {
1937 gi->gl = NULL;
1938 return;
1939 }
1940 n = 0;
1941 } else if (gi->sdp == gi->gl->gl_name.ln_sbd &&
1942 !__lockref_is_dead(&gi->gl->gl_lockref)) {
1943 if (!n--)
1944 break;
1932 } 1945 }
1933 /* Skip entries for other sb and dead entries */ 1946 gi->gl = rhashtable_walk_next(&gi->hti);
1934 if (gi->sdp == gi->gl->gl_name.ln_sbd &&
1935 !__lockref_is_dead(&gi->gl->gl_lockref))
1936 return;
1937 } 1947 }
1938} 1948}
1939 1949
@@ -1941,18 +1951,24 @@ static void *gfs2_glock_seq_start(struct seq_file *seq, loff_t *pos)
1941 __acquires(RCU) 1951 __acquires(RCU)
1942{ 1952{
1943 struct gfs2_glock_iter *gi = seq->private; 1953 struct gfs2_glock_iter *gi = seq->private;
1944 loff_t n = *pos; 1954 loff_t n;
1945 1955
1946 rhashtable_walk_enter(&gl_hash_table, &gi->hti); 1956 /*
1947 if (rhashtable_walk_start_check(&gi->hti) != 0) 1957 * We can either stay where we are, skip to the next hash table
1948 return NULL; 1958 * entry, or start from the beginning.
1959 */
1960 if (*pos < gi->last_pos) {
1961 rhashtable_walk_exit(&gi->hti);
1962 rhashtable_walk_enter(&gl_hash_table, &gi->hti);
1963 n = *pos + 1;
1964 } else {
1965 n = *pos - gi->last_pos;
1966 }
1949 1967
1950 do { 1968 rhashtable_walk_start(&gi->hti);
1951 gfs2_glock_iter_next(gi);
1952 } while (gi->gl && n--);
1953 1969
1970 gfs2_glock_iter_next(gi, n);
1954 gi->last_pos = *pos; 1971 gi->last_pos = *pos;
1955
1956 return gi->gl; 1972 return gi->gl;
1957} 1973}
1958 1974
@@ -1963,8 +1979,7 @@ static void *gfs2_glock_seq_next(struct seq_file *seq, void *iter_ptr,
1963 1979
1964 (*pos)++; 1980 (*pos)++;
1965 gi->last_pos = *pos; 1981 gi->last_pos = *pos;
1966 gfs2_glock_iter_next(gi); 1982 gfs2_glock_iter_next(gi, 1);
1967
1968 return gi->gl; 1983 return gi->gl;
1969} 1984}
1970 1985
@@ -1975,7 +1990,6 @@ static void gfs2_glock_seq_stop(struct seq_file *seq, void *iter_ptr)
1975 1990
1976 gi->gl = NULL; 1991 gi->gl = NULL;
1977 rhashtable_walk_stop(&gi->hti); 1992 rhashtable_walk_stop(&gi->hti);
1978 rhashtable_walk_exit(&gi->hti);
1979} 1993}
1980 1994
1981static int gfs2_glock_seq_show(struct seq_file *seq, void *iter_ptr) 1995static int gfs2_glock_seq_show(struct seq_file *seq, void *iter_ptr)
@@ -2041,7 +2055,13 @@ static int __gfs2_glocks_open(struct inode *inode, struct file *file,
2041 seq->buf = kmalloc(GFS2_SEQ_GOODSIZE, GFP_KERNEL | __GFP_NOWARN); 2055 seq->buf = kmalloc(GFS2_SEQ_GOODSIZE, GFP_KERNEL | __GFP_NOWARN);
2042 if (seq->buf) 2056 if (seq->buf)
2043 seq->size = GFS2_SEQ_GOODSIZE; 2057 seq->size = GFS2_SEQ_GOODSIZE;
2058 /*
2059 * Initially, we are "before" the first hash table entry; the
2060 * first call to rhashtable_walk_next gets us the first entry.
2061 */
2062 gi->last_pos = -1;
2044 gi->gl = NULL; 2063 gi->gl = NULL;
2064 rhashtable_walk_enter(&gl_hash_table, &gi->hti);
2045 } 2065 }
2046 return ret; 2066 return ret;
2047} 2067}
@@ -2057,6 +2077,7 @@ static int gfs2_glocks_release(struct inode *inode, struct file *file)
2057 struct gfs2_glock_iter *gi = seq->private; 2077 struct gfs2_glock_iter *gi = seq->private;
2058 2078
2059 gi->gl = NULL; 2079 gi->gl = NULL;
2080 rhashtable_walk_exit(&gi->hti);
2060 return seq_release_private(inode, file); 2081 return seq_release_private(inode, file);
2061} 2082}
2062 2083