gfs2: Stop using rhashtable_walk_peek

Function rhashtable_walk_peek is problematic because there is no
guarantee that the glock previously returned still exists; when that key
is deleted, rhashtable_walk_peek can end up returning a different key,
which will cause an inconsistent glock dump.  Fix this by keeping track
of the current glock in the seq file iterator functions instead.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
This commit is contained in:
Andreas Gruenbacher 2018-03-28 12:05:35 +02:00 committed by Bob Peterson
parent 450b1f6f56
commit 3fd5d3ad35

View File

@ -1923,28 +1923,37 @@ void gfs2_glock_exit(void)
static void gfs2_glock_iter_next(struct gfs2_glock_iter *gi, loff_t n) static void gfs2_glock_iter_next(struct gfs2_glock_iter *gi, loff_t n)
{ {
if (n == 0) struct gfs2_glock *gl = gi->gl;
gi->gl = rhashtable_walk_peek(&gi->hti);
else { if (gl) {
gi->gl = rhashtable_walk_next(&gi->hti); if (n == 0)
n--; return;
if (!lockref_put_not_zero(&gl->gl_lockref))
gfs2_glock_queue_put(gl);
} }
for (;;) { for (;;) {
if (IS_ERR_OR_NULL(gi->gl)) { gl = rhashtable_walk_next(&gi->hti);
if (!gi->gl) if (IS_ERR_OR_NULL(gl)) {
return; if (gl == ERR_PTR(-EAGAIN)) {
if (PTR_ERR(gi->gl) != -EAGAIN) { n = 1;
gi->gl = NULL; continue;
return;
} }
n = 0; gl = NULL;
} else if (gi->sdp == gi->gl->gl_name.ln_sbd && break;
!__lockref_is_dead(&gi->gl->gl_lockref)) { }
if (!n--) if (gl->gl_name.ln_sbd != gi->sdp)
break; continue;
if (n <= 1) {
if (!lockref_get_not_dead(&gl->gl_lockref))
continue;
break;
} else {
if (__lockref_is_dead(&gl->gl_lockref))
continue;
n--;
} }
gi->gl = rhashtable_walk_next(&gi->hti);
} }
gi->gl = gl;
} }
static void *gfs2_glock_seq_start(struct seq_file *seq, loff_t *pos) static void *gfs2_glock_seq_start(struct seq_file *seq, loff_t *pos)
@ -1988,7 +1997,6 @@ static void gfs2_glock_seq_stop(struct seq_file *seq, void *iter_ptr)
{ {
struct gfs2_glock_iter *gi = seq->private; struct gfs2_glock_iter *gi = seq->private;
gi->gl = NULL;
rhashtable_walk_stop(&gi->hti); rhashtable_walk_stop(&gi->hti);
} }
@ -2076,7 +2084,8 @@ static int gfs2_glocks_release(struct inode *inode, struct file *file)
struct seq_file *seq = file->private_data; struct seq_file *seq = file->private_data;
struct gfs2_glock_iter *gi = seq->private; struct gfs2_glock_iter *gi = seq->private;
gi->gl = NULL; if (gi->gl)
gfs2_glock_put(gi->gl);
rhashtable_walk_exit(&gi->hti); rhashtable_walk_exit(&gi->hti);
return seq_release_private(inode, file); return seq_release_private(inode, file);
} }