diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2007-07-24 08:53:36 -0400 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2007-10-10 03:54:49 -0400 |
commit | 7b08fc620109c2f66575e9ae884f45c37933ea18 (patch) | |
tree | 17fd00263b24dfd88242648a7bbd4de73826daec | |
parent | afd0942d98f74296b74993739e41d2ca7cb9fd5a (diff) |
[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>
-rw-r--r-- | fs/gfs2/glock.c | 73 |
1 files changed, 35 insertions, 38 deletions
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index d403fd708075..e4bc8ae561aa 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c | |||
@@ -46,7 +46,6 @@ struct glock_iter { | |||
46 | int hash; /* hash bucket index */ | 46 | int hash; /* hash bucket index */ |
47 | struct gfs2_sbd *sdp; /* incore superblock */ | 47 | struct gfs2_sbd *sdp; /* incore superblock */ |
48 | struct gfs2_glock *gl; /* current glock struct */ | 48 | struct gfs2_glock *gl; /* current glock struct */ |
49 | struct hlist_head *hb_list; /* current hash bucket ptr */ | ||
50 | struct seq_file *seq; /* sequence file for debugfs */ | 49 | struct seq_file *seq; /* sequence file for debugfs */ |
51 | char string[512]; /* scratch space */ | 50 | char string[512]; /* scratch space */ |
52 | }; | 51 | }; |
@@ -1990,47 +1989,38 @@ int __init gfs2_glock_init(void) | |||
1990 | 1989 | ||
1991 | static int gfs2_glock_iter_next(struct glock_iter *gi) | 1990 | static int gfs2_glock_iter_next(struct glock_iter *gi) |
1992 | { | 1991 | { |
1992 | struct gfs2_glock *gl; | ||
1993 | |||
1993 | read_lock(gl_lock_addr(gi->hash)); | 1994 | read_lock(gl_lock_addr(gi->hash)); |
1994 | while (1) { | 1995 | gl = gi->gl; |
1995 | if (!gi->hb_list) { /* If we don't have a hash bucket yet */ | 1996 | if (gl) { |
1996 | gi->hb_list = &gl_hash_table[gi->hash].hb_list; | 1997 | gi->gl = hlist_entry(gl->gl_list.next, struct gfs2_glock, |
1997 | if (hlist_empty(gi->hb_list)) { | 1998 | gl_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 | } | ||
2025 | if (gi->gl) | 1999 | if (gi->gl) |
2026 | break; | 2000 | gfs2_glock_hold(gi->gl); |
2027 | } | 2001 | } |
2028 | read_unlock(gl_lock_addr(gi->hash)); | 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 | return 0; | 2017 | return 0; |
2030 | } | 2018 | } |
2031 | 2019 | ||
2032 | static void gfs2_glock_iter_free(struct glock_iter *gi) | 2020 | static void gfs2_glock_iter_free(struct glock_iter *gi) |
2033 | { | 2021 | { |
2022 | if (gi->gl) | ||
2023 | gfs2_glock_put(gi->gl); | ||
2034 | kfree(gi); | 2024 | kfree(gi); |
2035 | } | 2025 | } |
2036 | 2026 | ||
@@ -2044,12 +2034,17 @@ static struct glock_iter *gfs2_glock_iter_init(struct gfs2_sbd *sdp) | |||
2044 | 2034 | ||
2045 | gi->sdp = sdp; | 2035 | gi->sdp = sdp; |
2046 | gi->hash = 0; | 2036 | gi->hash = 0; |
2047 | gi->gl = NULL; | ||
2048 | gi->hb_list = NULL; | ||
2049 | gi->seq = NULL; | 2037 | gi->seq = NULL; |
2050 | memset(gi->string, 0, sizeof(gi->string)); | 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 | gfs2_glock_iter_free(gi); | 2048 | gfs2_glock_iter_free(gi); |
2054 | return NULL; | 2049 | return NULL; |
2055 | } | 2050 | } |
@@ -2066,7 +2061,7 @@ static void *gfs2_glock_seq_start(struct seq_file *file, loff_t *pos) | |||
2066 | if (!gi) | 2061 | if (!gi) |
2067 | return NULL; | 2062 | return NULL; |
2068 | 2063 | ||
2069 | while (n--) { | 2064 | while(n--) { |
2070 | if (gfs2_glock_iter_next(gi)) { | 2065 | if (gfs2_glock_iter_next(gi)) { |
2071 | gfs2_glock_iter_free(gi); | 2066 | gfs2_glock_iter_free(gi); |
2072 | return NULL; | 2067 | return NULL; |
@@ -2093,7 +2088,9 @@ static void *gfs2_glock_seq_next(struct seq_file *file, void *iter_ptr, | |||
2093 | 2088 | ||
2094 | static void gfs2_glock_seq_stop(struct seq_file *file, void *iter_ptr) | 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 | static int gfs2_glock_seq_show(struct seq_file *file, void *iter_ptr) | 2096 | static int gfs2_glock_seq_show(struct seq_file *file, void *iter_ptr) |