Commit 7b08fc620109c2f66575e9ae884f45c37933ea18
1 parent
afd0942d98
Exists in
master
and in
20 other branches
[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: Steven Whitehouse <swhiteho@redhat.com>
Showing 1 changed file with 35 additions and 38 deletions Side-by-side Diff
fs/gfs2/glock.c
... | ... | @@ -46,7 +46,6 @@ |
46 | 46 | int hash; /* hash bucket index */ |
47 | 47 | struct gfs2_sbd *sdp; /* incore superblock */ |
48 | 48 | struct gfs2_glock *gl; /* current glock struct */ |
49 | - struct hlist_head *hb_list; /* current hash bucket ptr */ | |
50 | 49 | struct seq_file *seq; /* sequence file for debugfs */ |
51 | 50 | char string[512]; /* scratch space */ |
52 | 51 | }; |
53 | 52 | |
54 | 53 | |
55 | 54 | |
56 | 55 | |
... | ... | @@ -1990,47 +1989,38 @@ |
1990 | 1989 | |
1991 | 1990 | static int gfs2_glock_iter_next(struct glock_iter *gi) |
1992 | 1991 | { |
1992 | + struct gfs2_glock *gl; | |
1993 | + | |
1993 | 1994 | read_lock(gl_lock_addr(gi->hash)); |
1994 | - while (1) { | |
1995 | - if (!gi->hb_list) { /* If we don't have a hash bucket yet */ | |
1996 | - gi->hb_list = &gl_hash_table[gi->hash].hb_list; | |
1997 | - if (hlist_empty(gi->hb_list)) { | |
1998 | - read_unlock(gl_lock_addr(gi->hash)); | |
1999 | - gi->hash++; | |
2000 | - read_lock(gl_lock_addr(gi->hash)); | |
2001 | - gi->hb_list = NULL; | |
2002 | - if (gi->hash >= GFS2_GL_HASH_SIZE) { | |
2003 | - read_unlock(gl_lock_addr(gi->hash)); | |
2004 | - return 1; | |
2005 | - } | |
2006 | - else | |
2007 | - continue; | |
2008 | - } | |
2009 | - if (!hlist_empty(gi->hb_list)) { | |
2010 | - gi->gl = list_entry(gi->hb_list->first, | |
2011 | - struct gfs2_glock, | |
2012 | - gl_list); | |
2013 | - } | |
2014 | - } else { | |
2015 | - if (gi->gl->gl_list.next == NULL) { | |
2016 | - read_unlock(gl_lock_addr(gi->hash)); | |
2017 | - gi->hash++; | |
2018 | - read_lock(gl_lock_addr(gi->hash)); | |
2019 | - gi->hb_list = NULL; | |
2020 | - continue; | |
2021 | - } | |
2022 | - gi->gl = list_entry(gi->gl->gl_list.next, | |
2023 | - struct gfs2_glock, gl_list); | |
2024 | - } | |
1995 | + gl = gi->gl; | |
1996 | + if (gl) { | |
1997 | + gi->gl = hlist_entry(gl->gl_list.next, struct gfs2_glock, | |
1998 | + gl_list); | |
2025 | 1999 | if (gi->gl) |
2026 | - break; | |
2000 | + gfs2_glock_hold(gi->gl); | |
2027 | 2001 | } |
2028 | 2002 | read_unlock(gl_lock_addr(gi->hash)); |
2003 | + if (gl) | |
2004 | + gfs2_glock_put(gl); | |
2005 | + | |
2006 | + while(gi->gl == NULL) { | |
2007 | + gi->hash++; | |
2008 | + if (gi->hash >= GFS2_GL_HASH_SIZE) | |
2009 | + return 1; | |
2010 | + read_lock(gl_lock_addr(gi->hash)); | |
2011 | + gi->gl = hlist_entry(gl_hash_table[gi->hash].hb_list.first, | |
2012 | + struct gfs2_glock, gl_list); | |
2013 | + if (gi->gl) | |
2014 | + gfs2_glock_hold(gi->gl); | |
2015 | + read_unlock(gl_lock_addr(gi->hash)); | |
2016 | + } | |
2029 | 2017 | return 0; |
2030 | 2018 | } |
2031 | 2019 | |
2032 | 2020 | static void gfs2_glock_iter_free(struct glock_iter *gi) |
2033 | 2021 | { |
2022 | + if (gi->gl) | |
2023 | + gfs2_glock_put(gi->gl); | |
2034 | 2024 | kfree(gi); |
2035 | 2025 | } |
2036 | 2026 | |
2037 | 2027 | |
... | ... | @@ -2044,12 +2034,17 @@ |
2044 | 2034 | |
2045 | 2035 | gi->sdp = sdp; |
2046 | 2036 | gi->hash = 0; |
2047 | - gi->gl = NULL; | |
2048 | - gi->hb_list = NULL; | |
2049 | 2037 | gi->seq = NULL; |
2050 | 2038 | memset(gi->string, 0, sizeof(gi->string)); |
2051 | 2039 | |
2052 | - if (gfs2_glock_iter_next(gi)) { | |
2040 | + read_lock(gl_lock_addr(gi->hash)); | |
2041 | + gi->gl = hlist_entry(gl_hash_table[gi->hash].hb_list.first, | |
2042 | + struct gfs2_glock, gl_list); | |
2043 | + if (gi->gl) | |
2044 | + gfs2_glock_hold(gi->gl); | |
2045 | + read_unlock(gl_lock_addr(gi->hash)); | |
2046 | + | |
2047 | + if (!gi->gl && gfs2_glock_iter_next(gi)) { | |
2053 | 2048 | gfs2_glock_iter_free(gi); |
2054 | 2049 | return NULL; |
2055 | 2050 | } |
... | ... | @@ -2066,7 +2061,7 @@ |
2066 | 2061 | if (!gi) |
2067 | 2062 | return NULL; |
2068 | 2063 | |
2069 | - while (n--) { | |
2064 | + while(n--) { | |
2070 | 2065 | if (gfs2_glock_iter_next(gi)) { |
2071 | 2066 | gfs2_glock_iter_free(gi); |
2072 | 2067 | return NULL; |
... | ... | @@ -2093,7 +2088,9 @@ |
2093 | 2088 | |
2094 | 2089 | static void gfs2_glock_seq_stop(struct seq_file *file, void *iter_ptr) |
2095 | 2090 | { |
2096 | - /* nothing for now */ | |
2091 | + struct glock_iter *gi = iter_ptr; | |
2092 | + if (gi) | |
2093 | + gfs2_glock_iter_free(gi); | |
2097 | 2094 | } |
2098 | 2095 | |
2099 | 2096 | static int gfs2_glock_seq_show(struct seq_file *file, void *iter_ptr) |