aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2012-06-08 06:16:22 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2012-06-08 06:16:22 -0400
commitba1ddcb6ca0c46edd275790d1e4e2cfd6219ce19 (patch)
tree76d134ba74c609f5afa66e0e5c4b8bc541fc84b3
parentdf5d2f5560a9c33129391a136ed9f0ac26abe69b (diff)
GFS2: Cache last hash bucket for glock seq_files
For the glocks and glstats seq_files, which are exposed via debugfs we should cache the most recent hash bucket, along with the offset into that bucket. This allows us to restart from that point, rather than having to begin at the beginning each time. This is an idea from Eric Dumazet, however I've slightly extended it so that if the position from which we are due to start is at any point beyond the last cached point, we start from the last cached point, plus whatever is the appropriate offset. I don't really expect people to be lseeking around these files, but if they did so with only positive offsets, then we'd still get some of the benefit of using a cached offset. With my simple test of around 200k entries in the file, I'm seeing an approx 10x speed up. Cc: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
-rw-r--r--fs/gfs2/glock.c29
1 files changed, 22 insertions, 7 deletions
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 1c4cddf42a66..3ad8cb3eeb88 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -46,10 +46,12 @@
46#include "trace_gfs2.h" 46#include "trace_gfs2.h"
47 47
48struct gfs2_glock_iter { 48struct gfs2_glock_iter {
49 int hash; /* hash bucket index */ 49 int hash; /* hash bucket index */
50 struct gfs2_sbd *sdp; /* incore superblock */ 50 unsigned nhash; /* Index within current bucket */
51 struct gfs2_glock *gl; /* current glock struct */ 51 struct gfs2_sbd *sdp; /* incore superblock */
52 char string[512]; /* scratch space */ 52 struct gfs2_glock *gl; /* current glock struct */
53 loff_t last_pos; /* last position */
54 char string[512]; /* scratch space */
53}; 55};
54 56
55typedef void (*glock_examiner) (struct gfs2_glock * gl); 57typedef void (*glock_examiner) (struct gfs2_glock * gl);
@@ -950,7 +952,7 @@ void gfs2_print_dbg(struct seq_file *seq, const char *fmt, ...)
950 if (seq) { 952 if (seq) {
951 struct gfs2_glock_iter *gi = seq->private; 953 struct gfs2_glock_iter *gi = seq->private;
952 vsprintf(gi->string, fmt, args); 954 vsprintf(gi->string, fmt, args);
953 seq_printf(seq, gi->string); 955 seq_puts(seq, gi->string);
954 } else { 956 } else {
955 vaf.fmt = fmt; 957 vaf.fmt = fmt;
956 vaf.va = &args; 958 vaf.va = &args;
@@ -1854,8 +1856,14 @@ static int gfs2_glock_iter_next(struct gfs2_glock_iter *gi)
1854 gl = gi->gl; 1856 gl = gi->gl;
1855 if (gl) { 1857 if (gl) {
1856 gi->gl = glock_hash_next(gl); 1858 gi->gl = glock_hash_next(gl);
1859 gi->nhash++;
1857 } else { 1860 } else {
1861 if (gi->hash >= GFS2_GL_HASH_SIZE) {
1862 rcu_read_unlock();
1863 return 1;
1864 }
1858 gi->gl = glock_hash_chain(gi->hash); 1865 gi->gl = glock_hash_chain(gi->hash);
1866 gi->nhash = 0;
1859 } 1867 }
1860 while (gi->gl == NULL) { 1868 while (gi->gl == NULL) {
1861 gi->hash++; 1869 gi->hash++;
@@ -1864,6 +1872,7 @@ static int gfs2_glock_iter_next(struct gfs2_glock_iter *gi)
1864 return 1; 1872 return 1;
1865 } 1873 }
1866 gi->gl = glock_hash_chain(gi->hash); 1874 gi->gl = glock_hash_chain(gi->hash);
1875 gi->nhash = 0;
1867 } 1876 }
1868 /* Skip entries for other sb and dead entries */ 1877 /* Skip entries for other sb and dead entries */
1869 } while (gi->sdp != gi->gl->gl_sbd || atomic_read(&gi->gl->gl_ref) == 0); 1878 } while (gi->sdp != gi->gl->gl_sbd || atomic_read(&gi->gl->gl_ref) == 0);
@@ -1876,7 +1885,12 @@ static void *gfs2_glock_seq_start(struct seq_file *seq, loff_t *pos)
1876 struct gfs2_glock_iter *gi = seq->private; 1885 struct gfs2_glock_iter *gi = seq->private;
1877 loff_t n = *pos; 1886 loff_t n = *pos;
1878 1887
1879 gi->hash = 0; 1888 if (gi->last_pos <= *pos)
1889 n = gi->nhash + (*pos - gi->last_pos);
1890 else
1891 gi->hash = 0;
1892
1893 gi->nhash = 0;
1880 rcu_read_lock(); 1894 rcu_read_lock();
1881 1895
1882 do { 1896 do {
@@ -1884,6 +1898,7 @@ static void *gfs2_glock_seq_start(struct seq_file *seq, loff_t *pos)
1884 return NULL; 1898 return NULL;
1885 } while (n--); 1899 } while (n--);
1886 1900
1901 gi->last_pos = *pos;
1887 return gi->gl; 1902 return gi->gl;
1888} 1903}
1889 1904
@@ -1893,7 +1908,7 @@ static void *gfs2_glock_seq_next(struct seq_file *seq, void *iter_ptr,
1893 struct gfs2_glock_iter *gi = seq->private; 1908 struct gfs2_glock_iter *gi = seq->private;
1894 1909
1895 (*pos)++; 1910 (*pos)++;
1896 1911 gi->last_pos = *pos;
1897 if (gfs2_glock_iter_next(gi)) 1912 if (gfs2_glock_iter_next(gi))
1898 return NULL; 1913 return NULL;
1899 1914