Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

+14 -11
+14 -11
fs/gfs2/trans.c
··· 176 176 INIT_LIST_HEAD(&bd->bd_list); 177 177 INIT_LIST_HEAD(&bd->bd_ail_st_list); 178 178 INIT_LIST_HEAD(&bd->bd_ail_gl_list); 179 - bh->b_private = bd; 180 179 return bd; 181 180 } 182 181 ··· 209 210 if (bd == NULL) { 210 211 spin_unlock(&sdp->sd_log_lock); 211 212 unlock_buffer(bh); 212 - if (bh->b_private == NULL) 213 - bd = gfs2_alloc_bufdata(gl, bh); 214 - else 215 - bd = bh->b_private; 213 + bd = gfs2_alloc_bufdata(gl, bh); 216 214 lock_buffer(bh); 217 215 spin_lock(&sdp->sd_log_lock); 216 + if (bh->b_private) { 217 + kmem_cache_free(gfs2_bufdata_cachep, bd); 218 + bd = bh->b_private; 219 + } else { 220 + bh->b_private = bd; 221 + } 218 222 } 219 223 gfs2_assert(sdp, bd->bd_gl == gl); 220 224 set_bit(TR_TOUCHED, &tr->tr_flags); ··· 273 271 if (bd == NULL) { 274 272 spin_unlock(&sdp->sd_log_lock); 275 273 unlock_buffer(bh); 276 - folio_lock(bh->b_folio); 277 - if (bh->b_private == NULL) 278 - bd = gfs2_alloc_bufdata(gl, bh); 279 - else 280 - bd = bh->b_private; 281 - folio_unlock(bh->b_folio); 274 + bd = gfs2_alloc_bufdata(gl, bh); 282 275 lock_buffer(bh); 283 276 spin_lock(&sdp->sd_log_lock); 277 + if (bh->b_private) { 278 + kmem_cache_free(gfs2_bufdata_cachep, bd); 279 + bd = bh->b_private; 280 + } else { 281 + bh->b_private = bd; 282 + } 284 283 } 285 284 gfs2_assert(sdp, bd->bd_gl == gl); 286 285 set_bit(TR_TOUCHED, &tr->tr_flags);