aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/glock.c
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2012-01-16 10:46:21 -0500
committerSteven Whitehouse <swhiteho@redhat.com>2012-02-28 04:43:07 -0500
commit4043b886b0740ded65f633fc4b7225d624c7e658 (patch)
tree532dc280a44a051b6a93d23702f8b847b07e5ff6 /fs/gfs2/glock.c
parent586c6e7013c8cbb8c91aaa6568ec349b1dc2c691 (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.c14
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
170static void gfs2_glock_remove_from_lru(struct gfs2_glock *gl) 170static 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
179static 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);