Commit 3fd5d3ad authored by Andreas Gruenbacher's avatar Andreas Gruenbacher Committed by Bob Peterson
Browse files

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: default avatarAndreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: default avatarBob Peterson <rpeterso@redhat.com>
parent 450b1f6f
Loading
Loading
Loading
Loading
+28 −19
Original line number Diff line number Diff line
@@ -1923,28 +1923,37 @@ void gfs2_glock_exit(void)

static void gfs2_glock_iter_next(struct gfs2_glock_iter *gi, loff_t n)
{
	struct gfs2_glock *gl = gi->gl;

	if (gl) {
		if (n == 0)
		gi->gl = rhashtable_walk_peek(&gi->hti);
	else {
		gi->gl = rhashtable_walk_next(&gi->hti);
		n--;
			return;
		if (!lockref_put_not_zero(&gl->gl_lockref))
			gfs2_glock_queue_put(gl);
	}
	for (;;) {
		if (IS_ERR_OR_NULL(gi->gl)) {
			if (!gi->gl)
				return;
			if (PTR_ERR(gi->gl) != -EAGAIN) {
				gi->gl = NULL;
				return;
		gl = rhashtable_walk_next(&gi->hti);
		if (IS_ERR_OR_NULL(gl)) {
			if (gl == ERR_PTR(-EAGAIN)) {
				n = 1;
				continue;
			}
			n = 0;
		} else if (gi->sdp == gi->gl->gl_name.ln_sbd &&
			   !__lockref_is_dead(&gi->gl->gl_lockref)) {
			if (!n--)
			gl = NULL;
			break;
		}
		gi->gl = rhashtable_walk_next(&gi->hti);
		if (gl->gl_name.ln_sbd != gi->sdp)
			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 = gl;
}

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;

	gi->gl = NULL;
	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 gfs2_glock_iter *gi = seq->private;

	gi->gl = NULL;
	if (gi->gl)
		gfs2_glock_put(gi->gl);
	rhashtable_walk_exit(&gi->hti);
	return seq_release_private(inode, file);
}