Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7b08fc62 authored by Steven Whitehouse's avatar Steven Whitehouse
Browse files

[GFS2] Fix an oops in glock dumping



This fixes an oops which was occurring during glock dumping due to the
seq file code not taking a reference to the glock. Also this fixes a
memory leak which occurred in certain cases, in turn preventing the
filesystem from unmounting.

Signed-off-by: default avatarSteven Whitehouse <swhiteho@redhat.com>
parent afd0942d
Loading
Loading
Loading
Loading
+35 −38
Original line number Original line Diff line number Diff line
@@ -46,7 +46,6 @@ struct glock_iter {
	int hash;                     /* hash bucket index         */
	int hash;                     /* hash bucket index         */
	struct gfs2_sbd *sdp;         /* incore superblock         */
	struct gfs2_sbd *sdp;         /* incore superblock         */
	struct gfs2_glock *gl;        /* current glock struct      */
	struct gfs2_glock *gl;        /* current glock struct      */
	struct hlist_head *hb_list;   /* current hash bucket ptr   */
	struct seq_file *seq;         /* sequence file for debugfs */
	struct seq_file *seq;         /* sequence file for debugfs */
	char string[512];             /* scratch space             */
	char string[512];             /* scratch space             */
};
};
@@ -1990,47 +1989,38 @@ int __init gfs2_glock_init(void)


static int gfs2_glock_iter_next(struct glock_iter *gi)
static int gfs2_glock_iter_next(struct glock_iter *gi)
{
{
	struct gfs2_glock *gl;

	read_lock(gl_lock_addr(gi->hash));
	read_lock(gl_lock_addr(gi->hash));
	while (1) {
	gl = gi->gl;
		if (!gi->hb_list) {  /* If we don't have a hash bucket yet */
	if (gl) {
			gi->hb_list = &gl_hash_table[gi->hash].hb_list;
		gi->gl = hlist_entry(gl->gl_list.next, struct gfs2_glock,
			if (hlist_empty(gi->hb_list)) {
				read_unlock(gl_lock_addr(gi->hash));
				gi->hash++;
				read_lock(gl_lock_addr(gi->hash));
				gi->hb_list = NULL;
				if (gi->hash >= GFS2_GL_HASH_SIZE) {
					read_unlock(gl_lock_addr(gi->hash));
					return 1;
				}
				else
					continue;
			}
			if (!hlist_empty(gi->hb_list)) {
				gi->gl = list_entry(gi->hb_list->first,
						    struct gfs2_glock,
				     gl_list);
				     gl_list);
		if (gi->gl)
			gfs2_glock_hold(gi->gl);
	}
	}
		} else {
			if (gi->gl->gl_list.next == NULL) {
	read_unlock(gl_lock_addr(gi->hash));
	read_unlock(gl_lock_addr(gi->hash));
	if (gl)
		gfs2_glock_put(gl);

	while(gi->gl == NULL) {
		gi->hash++;
		gi->hash++;
		if (gi->hash >= GFS2_GL_HASH_SIZE)
			return 1;
		read_lock(gl_lock_addr(gi->hash));
		read_lock(gl_lock_addr(gi->hash));
				gi->hb_list = NULL;
		gi->gl = hlist_entry(gl_hash_table[gi->hash].hb_list.first,
				continue;
			}
			gi->gl = list_entry(gi->gl->gl_list.next,
				     struct gfs2_glock, gl_list);
				     struct gfs2_glock, gl_list);
		}
		if (gi->gl)
		if (gi->gl)
			break;
			gfs2_glock_hold(gi->gl);
	}
		read_unlock(gl_lock_addr(gi->hash));
		read_unlock(gl_lock_addr(gi->hash));
	}
	return 0;
	return 0;
}
}


static void gfs2_glock_iter_free(struct glock_iter *gi)
static void gfs2_glock_iter_free(struct glock_iter *gi)
{
{
	if (gi->gl)
		gfs2_glock_put(gi->gl);
	kfree(gi);
	kfree(gi);
}
}


@@ -2044,12 +2034,17 @@ static struct glock_iter *gfs2_glock_iter_init(struct gfs2_sbd *sdp)


	gi->sdp = sdp;
	gi->sdp = sdp;
	gi->hash = 0;
	gi->hash = 0;
	gi->gl = NULL;
	gi->hb_list = NULL;
	gi->seq = NULL;
	gi->seq = NULL;
	memset(gi->string, 0, sizeof(gi->string));
	memset(gi->string, 0, sizeof(gi->string));


	if (gfs2_glock_iter_next(gi)) {
	read_lock(gl_lock_addr(gi->hash));
	gi->gl = hlist_entry(gl_hash_table[gi->hash].hb_list.first,
			     struct gfs2_glock, gl_list);
	if (gi->gl)
		gfs2_glock_hold(gi->gl);
	read_unlock(gl_lock_addr(gi->hash));

	if (!gi->gl && gfs2_glock_iter_next(gi)) {
		gfs2_glock_iter_free(gi);
		gfs2_glock_iter_free(gi);
		return NULL;
		return NULL;
	}
	}
@@ -2093,7 +2088,9 @@ static void *gfs2_glock_seq_next(struct seq_file *file, void *iter_ptr,


static void gfs2_glock_seq_stop(struct seq_file *file, void *iter_ptr)
static void gfs2_glock_seq_stop(struct seq_file *file, void *iter_ptr)
{
{
	/* nothing for now */
	struct glock_iter *gi = iter_ptr;
	if (gi)
		gfs2_glock_iter_free(gi);
}
}


static int gfs2_glock_seq_show(struct seq_file *file, void *iter_ptr)
static int gfs2_glock_seq_show(struct seq_file *file, void *iter_ptr)