diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2012-01-16 10:46:21 -0500 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2012-02-28 04:43:07 -0500 |
commit | 4043b886b0740ded65f633fc4b7225d624c7e658 (patch) | |
tree | 532dc280a44a051b6a93d23702f8b847b07e5ff6 /fs/gfs2/glock.c | |
parent | 586c6e7013c8cbb8c91aaa6568ec349b1dc2c691 (diff) |
GFS2: Fix race between lru_list and glock ref count
This patch fixes a narrow race window between the glock ref count
hitting zero and glocks being removed from the lru_list.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/glock.c')
-rw-r--r-- | fs/gfs2/glock.c | 14 |
1 files changed, 10 insertions, 4 deletions
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 376816fcd040..351a3e797789 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c | |||
@@ -167,14 +167,19 @@ void gfs2_glock_add_to_lru(struct gfs2_glock *gl) | |||
167 | spin_unlock(&lru_lock); | 167 | spin_unlock(&lru_lock); |
168 | } | 168 | } |
169 | 169 | ||
170 | static void gfs2_glock_remove_from_lru(struct gfs2_glock *gl) | 170 | static void __gfs2_glock_remove_from_lru(struct gfs2_glock *gl) |
171 | { | 171 | { |
172 | spin_lock(&lru_lock); | ||
173 | if (!list_empty(&gl->gl_lru)) { | 172 | if (!list_empty(&gl->gl_lru)) { |
174 | list_del_init(&gl->gl_lru); | 173 | list_del_init(&gl->gl_lru); |
175 | atomic_dec(&lru_count); | 174 | atomic_dec(&lru_count); |
176 | clear_bit(GLF_LRU, &gl->gl_flags); | 175 | clear_bit(GLF_LRU, &gl->gl_flags); |
177 | } | 176 | } |
177 | } | ||
178 | |||
179 | static void gfs2_glock_remove_from_lru(struct gfs2_glock *gl) | ||
180 | { | ||
181 | spin_lock(&lru_lock); | ||
182 | __gfs2_glock_remove_from_lru(gl); | ||
178 | spin_unlock(&lru_lock); | 183 | spin_unlock(&lru_lock); |
179 | } | 184 | } |
180 | 185 | ||
@@ -217,11 +222,12 @@ void gfs2_glock_put(struct gfs2_glock *gl) | |||
217 | struct gfs2_sbd *sdp = gl->gl_sbd; | 222 | struct gfs2_sbd *sdp = gl->gl_sbd; |
218 | struct address_space *mapping = gfs2_glock2aspace(gl); | 223 | struct address_space *mapping = gfs2_glock2aspace(gl); |
219 | 224 | ||
220 | if (atomic_dec_and_test(&gl->gl_ref)) { | 225 | if (atomic_dec_and_lock(&gl->gl_ref, &lru_lock)) { |
226 | __gfs2_glock_remove_from_lru(gl); | ||
227 | spin_unlock(&lru_lock); | ||
221 | spin_lock_bucket(gl->gl_hash); | 228 | spin_lock_bucket(gl->gl_hash); |
222 | hlist_bl_del_rcu(&gl->gl_list); | 229 | hlist_bl_del_rcu(&gl->gl_list); |
223 | spin_unlock_bucket(gl->gl_hash); | 230 | spin_unlock_bucket(gl->gl_hash); |
224 | gfs2_glock_remove_from_lru(gl); | ||
225 | GLOCK_BUG_ON(gl, !list_empty(&gl->gl_holders)); | 231 | GLOCK_BUG_ON(gl, !list_empty(&gl->gl_holders)); |
226 | GLOCK_BUG_ON(gl, mapping && mapping->nrpages); | 232 | GLOCK_BUG_ON(gl, mapping && mapping->nrpages); |
227 | trace_gfs2_glock_put(gl); | 233 | trace_gfs2_glock_put(gl); |