aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorAbhijith Das <adas@redhat.com>2007-11-29 15:13:54 -0500
committerSteven Whitehouse <swhiteho@redhat.com>2008-01-25 03:08:18 -0500
commit292c8c14cace19c94c6abe25506310239daf949e (patch)
tree3b1b1407e00abc154768dc2f5a684b0fcf0cbd1f /fs
parentc97bfe4351771675963e02f34d31e206fd2d7150 (diff)
[GFS2] patch to check for recursive lock requests in gfs2_rename code 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 <adas@redhat.com> Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/gfs2/rgrp.c33
1 files changed, 25 insertions, 8 deletions
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
index 09848aac45f6..e0ee195558d3 100644
--- a/fs/gfs2/rgrp.c
+++ b/fs/gfs2/rgrp.c
@@ -1063,22 +1063,30 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
1063 int flags = LM_FLAG_TRY; 1063 int flags = LM_FLAG_TRY;
1064 int skipped = 0; 1064 int skipped = 0;
1065 int loops = 0; 1065 int loops = 0;
1066 int error; 1066 int error, rg_locked;
1067 1067
1068 /* Try recently successful rgrps */ 1068 /* Try recently successful rgrps */
1069 1069
1070 rgd = recent_rgrp_first(sdp, ip->i_last_rg_alloc); 1070 rgd = recent_rgrp_first(sdp, ip->i_last_rg_alloc);
1071 1071
1072 while (rgd) { 1072 while (rgd) {
1073 error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 1073 rg_locked = 0;
1074 LM_FLAG_TRY, &al->al_rgd_gh); 1074
1075 if (gfs2_glock_is_locked_by_me(rgd->rd_gl)) {
1076 rg_locked = 1;
1077 error = 0;
1078 } else {
1079 error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE,
1080 LM_FLAG_TRY, &al->al_rgd_gh);
1081 }
1075 switch (error) { 1082 switch (error) {
1076 case 0: 1083 case 0:
1077 if (try_rgrp_fit(rgd, al)) 1084 if (try_rgrp_fit(rgd, al))
1078 goto out; 1085 goto out;
1079 if (rgd->rd_flags & GFS2_RDF_CHECK) 1086 if (rgd->rd_flags & GFS2_RDF_CHECK)
1080 inode = try_rgrp_unlink(rgd, last_unlinked); 1087 inode = try_rgrp_unlink(rgd, last_unlinked);
1081 gfs2_glock_dq_uninit(&al->al_rgd_gh); 1088 if (!rg_locked)
1089 gfs2_glock_dq_uninit(&al->al_rgd_gh);
1082 if (inode) 1090 if (inode)
1083 return inode; 1091 return inode;
1084 rgd = recent_rgrp_next(rgd, 1); 1092 rgd = recent_rgrp_next(rgd, 1);
@@ -1098,15 +1106,23 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
1098 begin = rgd = forward_rgrp_get(sdp); 1106 begin = rgd = forward_rgrp_get(sdp);
1099 1107
1100 for (;;) { 1108 for (;;) {
1101 error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, flags, 1109 rg_locked = 0;
1102 &al->al_rgd_gh); 1110
1111 if (gfs2_glock_is_locked_by_me(rgd->rd_gl)) {
1112 rg_locked = 1;
1113 error = 0;
1114 } else {
1115 error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, flags,
1116 &al->al_rgd_gh);
1117 }
1103 switch (error) { 1118 switch (error) {
1104 case 0: 1119 case 0:
1105 if (try_rgrp_fit(rgd, al)) 1120 if (try_rgrp_fit(rgd, al))
1106 goto out; 1121 goto out;
1107 if (rgd->rd_flags & GFS2_RDF_CHECK) 1122 if (rgd->rd_flags & GFS2_RDF_CHECK)
1108 inode = try_rgrp_unlink(rgd, last_unlinked); 1123 inode = try_rgrp_unlink(rgd, last_unlinked);
1109 gfs2_glock_dq_uninit(&al->al_rgd_gh); 1124 if (!rg_locked)
1125 gfs2_glock_dq_uninit(&al->al_rgd_gh);
1110 if (inode) 1126 if (inode)
1111 return inode; 1127 return inode;
1112 break; 1128 break;
@@ -1213,7 +1229,8 @@ void gfs2_inplace_release(struct gfs2_inode *ip)
1213 al->al_line); 1229 al->al_line);
1214 1230
1215 al->al_rgd = NULL; 1231 al->al_rgd = NULL;
1216 gfs2_glock_dq_uninit(&al->al_rgd_gh); 1232 if (al->al_rgd_gh.gh_gl)
1233 gfs2_glock_dq_uninit(&al->al_rgd_gh);
1217 if (ip != GFS2_I(sdp->sd_rindex)) 1234 if (ip != GFS2_I(sdp->sd_rindex))
1218 gfs2_glock_dq_uninit(&al->al_ri_gh); 1235 gfs2_glock_dq_uninit(&al->al_ri_gh);
1219} 1236}