Skip to content

Commit

Permalink
[GFS2] patch to check for recursive lock requests in gfs2_rename code…
Browse files Browse the repository at this point in the history
… path

A certain scenario in the rename code path triggers a kernel BUG()
because it accidentally does recursive locking The first lock is
requested to unlink an already existing inode (replacing a file) and the
second lock is requested when the destination directory needs to alloc
some space. It is rare that these two
events happen during the same rename call, and even more rare that these
two instances try to lock the same rgrp. It is, however, possible.
https://bugzilla.redhat.com/show_bug.cgi?id=404711

Signed-off-by: Abhijith Das <[email protected]>
Signed-off-by: Steven Whitehouse <[email protected]>
  • Loading branch information
Abhijith Das authored and swhiteho committed Jan 25, 2008
1 parent c97bfe4 commit 292c8c1
Showing 1 changed file with 25 additions and 8 deletions.
33 changes: 25 additions & 8 deletions fs/gfs2/rgrp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1063,22 +1063,30 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
int flags = LM_FLAG_TRY;
int skipped = 0;
int loops = 0;
int error;
int error, rg_locked;

/* Try recently successful rgrps */

rgd = recent_rgrp_first(sdp, ip->i_last_rg_alloc);

while (rgd) {
error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE,
LM_FLAG_TRY, &al->al_rgd_gh);
rg_locked = 0;

if (gfs2_glock_is_locked_by_me(rgd->rd_gl)) {
rg_locked = 1;
error = 0;
} else {
error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE,
LM_FLAG_TRY, &al->al_rgd_gh);
}
switch (error) {
case 0:
if (try_rgrp_fit(rgd, al))
goto out;
if (rgd->rd_flags & GFS2_RDF_CHECK)
inode = try_rgrp_unlink(rgd, last_unlinked);
gfs2_glock_dq_uninit(&al->al_rgd_gh);
if (!rg_locked)
gfs2_glock_dq_uninit(&al->al_rgd_gh);
if (inode)
return inode;
rgd = recent_rgrp_next(rgd, 1);
Expand All @@ -1098,15 +1106,23 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
begin = rgd = forward_rgrp_get(sdp);

for (;;) {
error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, flags,
&al->al_rgd_gh);
rg_locked = 0;

if (gfs2_glock_is_locked_by_me(rgd->rd_gl)) {
rg_locked = 1;
error = 0;
} else {
error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, flags,
&al->al_rgd_gh);
}
switch (error) {
case 0:
if (try_rgrp_fit(rgd, al))
goto out;
if (rgd->rd_flags & GFS2_RDF_CHECK)
inode = try_rgrp_unlink(rgd, last_unlinked);
gfs2_glock_dq_uninit(&al->al_rgd_gh);
if (!rg_locked)
gfs2_glock_dq_uninit(&al->al_rgd_gh);
if (inode)
return inode;
break;
Expand Down Expand Up @@ -1213,7 +1229,8 @@ void gfs2_inplace_release(struct gfs2_inode *ip)
al->al_line);

al->al_rgd = NULL;
gfs2_glock_dq_uninit(&al->al_rgd_gh);
if (al->al_rgd_gh.gh_gl)
gfs2_glock_dq_uninit(&al->al_rgd_gh);
if (ip != GFS2_I(sdp->sd_rindex))
gfs2_glock_dq_uninit(&al->al_ri_gh);
}
Expand Down

0 comments on commit 292c8c1

Please sign in to comment.