Skip to content

Commit 6e1a833

Browse files
author
Andreas Gruenbacher
committed
gfs2: bufdata allocation race
The locking in gfs2_trans_add_data() and gfs2_trans_add_meta() doesn't follow the usual coding pattern of checking bh->b_private under lock, allocating a new bufdata object with the locks dropped, and re-checking once the lock has been reacquired. Both functions set bh->b_private without holding the buffer lock. Fix that. Also, in gfs2_trans_add_meta(), taking the folio lock during the allocation doesn't actually do anything useful. Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
1 parent 9e34adb commit 6e1a833

1 file changed

Lines changed: 14 additions & 11 deletions

File tree

fs/gfs2/trans.c

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,6 @@ static struct gfs2_bufdata *gfs2_alloc_bufdata(struct gfs2_glock *gl,
176176
INIT_LIST_HEAD(&bd->bd_list);
177177
INIT_LIST_HEAD(&bd->bd_ail_st_list);
178178
INIT_LIST_HEAD(&bd->bd_ail_gl_list);
179-
bh->b_private = bd;
180179
return bd;
181180
}
182181

@@ -210,12 +209,15 @@ void gfs2_trans_add_data(struct gfs2_glock *gl, struct buffer_head *bh)
210209
if (bd == NULL) {
211210
spin_unlock(&sdp->sd_log_lock);
212211
unlock_buffer(bh);
213-
if (bh->b_private == NULL)
214-
bd = gfs2_alloc_bufdata(gl, bh);
215-
else
216-
bd = bh->b_private;
212+
bd = gfs2_alloc_bufdata(gl, bh);
217213
lock_buffer(bh);
218214
spin_lock(&sdp->sd_log_lock);
215+
if (bh->b_private) {
216+
kmem_cache_free(gfs2_bufdata_cachep, bd);
217+
bd = bh->b_private;
218+
} else {
219+
bh->b_private = bd;
220+
}
219221
}
220222
gfs2_assert(sdp, bd->bd_gl == gl);
221223
set_bit(TR_TOUCHED, &tr->tr_flags);
@@ -271,14 +273,15 @@ void gfs2_trans_add_meta(struct gfs2_glock *gl, struct buffer_head *bh)
271273
if (bd == NULL) {
272274
spin_unlock(&sdp->sd_log_lock);
273275
unlock_buffer(bh);
274-
folio_lock(bh->b_folio);
275-
if (bh->b_private == NULL)
276-
bd = gfs2_alloc_bufdata(gl, bh);
277-
else
278-
bd = bh->b_private;
279-
folio_unlock(bh->b_folio);
276+
bd = gfs2_alloc_bufdata(gl, bh);
280277
lock_buffer(bh);
281278
spin_lock(&sdp->sd_log_lock);
279+
if (bh->b_private) {
280+
kmem_cache_free(gfs2_bufdata_cachep, bd);
281+
bd = bh->b_private;
282+
} else {
283+
bh->b_private = bd;
284+
}
282285
}
283286
gfs2_assert(sdp, bd->bd_gl == gl);
284287
set_bit(TR_TOUCHED, &tr->tr_flags);

0 commit comments

Comments
 (0)