diff options
author | Bob Peterson <rpeterso@redhat.com> | 2010-05-11 17:58:11 -0400 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2010-05-12 04:55:39 -0400 |
commit | cc0581bd6132984641e47809552fc9d5dfcadbcf (patch) | |
tree | 21a75ca6f00e99661d679a09c5c8e01e8e61c40e /fs/gfs2/rgrp.c | |
parent | eaefbf968a83a160324225fb2ac9c49e56c86515 (diff) |
GFS2: stuck in inode wait, no glocks stuck
This patch changes the lock ordering when gfs2 reclaims
unlinked dinodes, thereby avoiding a livelock.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/rgrp.c')
-rw-r--r-- | fs/gfs2/rgrp.c | 78 |
1 files changed, 30 insertions, 48 deletions
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 37391550284f..8bce73ed4d8e 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c | |||
@@ -952,16 +952,14 @@ static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_alloc *al) | |||
952 | * The inode, if one has been found, in inode. | 952 | * The inode, if one has been found, in inode. |
953 | */ | 953 | */ |
954 | 954 | ||
955 | static int try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked, | 955 | static u64 try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked, |
956 | u64 skip, struct inode **inode) | 956 | u64 skip) |
957 | { | 957 | { |
958 | u32 goal = 0, block; | 958 | u32 goal = 0, block; |
959 | u64 no_addr; | 959 | u64 no_addr; |
960 | struct gfs2_sbd *sdp = rgd->rd_sbd; | 960 | struct gfs2_sbd *sdp = rgd->rd_sbd; |
961 | unsigned int n; | 961 | unsigned int n; |
962 | int error = 0; | ||
963 | 962 | ||
964 | *inode = NULL; | ||
965 | for(;;) { | 963 | for(;;) { |
966 | if (goal >= rgd->rd_data) | 964 | if (goal >= rgd->rd_data) |
967 | break; | 965 | break; |
@@ -981,10 +979,7 @@ static int try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked, | |||
981 | if (no_addr == skip) | 979 | if (no_addr == skip) |
982 | continue; | 980 | continue; |
983 | *last_unlinked = no_addr; | 981 | *last_unlinked = no_addr; |
984 | error = gfs2_unlinked_inode_lookup(rgd->rd_sbd->sd_vfs, | 982 | return no_addr; |
985 | no_addr, inode); | ||
986 | if (*inode || error) | ||
987 | return error; | ||
988 | } | 983 | } |
989 | 984 | ||
990 | rgd->rd_flags &= ~GFS2_RDF_CHECK; | 985 | rgd->rd_flags &= ~GFS2_RDF_CHECK; |
@@ -1069,11 +1064,12 @@ static void forward_rgrp_set(struct gfs2_sbd *sdp, struct gfs2_rgrpd *rgd) | |||
1069 | * Try to acquire rgrp in way which avoids contending with others. | 1064 | * Try to acquire rgrp in way which avoids contending with others. |
1070 | * | 1065 | * |
1071 | * Returns: errno | 1066 | * Returns: errno |
1067 | * unlinked: the block address of an unlinked block to be reclaimed | ||
1072 | */ | 1068 | */ |
1073 | 1069 | ||
1074 | static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked) | 1070 | static int get_local_rgrp(struct gfs2_inode *ip, u64 *unlinked, |
1071 | u64 *last_unlinked) | ||
1075 | { | 1072 | { |
1076 | struct inode *inode = NULL; | ||
1077 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 1073 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
1078 | struct gfs2_rgrpd *rgd, *begin = NULL; | 1074 | struct gfs2_rgrpd *rgd, *begin = NULL; |
1079 | struct gfs2_alloc *al = ip->i_alloc; | 1075 | struct gfs2_alloc *al = ip->i_alloc; |
@@ -1082,6 +1078,7 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked) | |||
1082 | int loops = 0; | 1078 | int loops = 0; |
1083 | int error, rg_locked; | 1079 | int error, rg_locked; |
1084 | 1080 | ||
1081 | *unlinked = 0; | ||
1085 | rgd = gfs2_blk2rgrpd(sdp, ip->i_goal); | 1082 | rgd = gfs2_blk2rgrpd(sdp, ip->i_goal); |
1086 | 1083 | ||
1087 | while (rgd) { | 1084 | while (rgd) { |
@@ -1103,29 +1100,19 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked) | |||
1103 | because that would require an iput which can only | 1100 | because that would require an iput which can only |
1104 | happen after the rgrp is unlocked. */ | 1101 | happen after the rgrp is unlocked. */ |
1105 | if (!rg_locked && rgd->rd_flags & GFS2_RDF_CHECK) | 1102 | if (!rg_locked && rgd->rd_flags & GFS2_RDF_CHECK) |
1106 | error = try_rgrp_unlink(rgd, last_unlinked, | 1103 | *unlinked = try_rgrp_unlink(rgd, last_unlinked, |
1107 | ip->i_no_addr, &inode); | 1104 | ip->i_no_addr); |
1108 | if (!rg_locked) | 1105 | if (!rg_locked) |
1109 | gfs2_glock_dq_uninit(&al->al_rgd_gh); | 1106 | gfs2_glock_dq_uninit(&al->al_rgd_gh); |
1110 | if (inode) { | 1107 | if (*unlinked) |
1111 | if (error) { | 1108 | return -EAGAIN; |
1112 | if (inode->i_state & I_NEW) | ||
1113 | iget_failed(inode); | ||
1114 | else | ||
1115 | iput(inode); | ||
1116 | return ERR_PTR(error); | ||
1117 | } | ||
1118 | return inode; | ||
1119 | } | ||
1120 | if (error) | ||
1121 | return ERR_PTR(error); | ||
1122 | /* fall through */ | 1109 | /* fall through */ |
1123 | case GLR_TRYFAILED: | 1110 | case GLR_TRYFAILED: |
1124 | rgd = recent_rgrp_next(rgd); | 1111 | rgd = recent_rgrp_next(rgd); |
1125 | break; | 1112 | break; |
1126 | 1113 | ||
1127 | default: | 1114 | default: |
1128 | return ERR_PTR(error); | 1115 | return error; |
1129 | } | 1116 | } |
1130 | } | 1117 | } |
1131 | 1118 | ||
@@ -1148,22 +1135,12 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked) | |||
1148 | if (try_rgrp_fit(rgd, al)) | 1135 | if (try_rgrp_fit(rgd, al)) |
1149 | goto out; | 1136 | goto out; |
1150 | if (!rg_locked && rgd->rd_flags & GFS2_RDF_CHECK) | 1137 | if (!rg_locked && rgd->rd_flags & GFS2_RDF_CHECK) |
1151 | error = try_rgrp_unlink(rgd, last_unlinked, | 1138 | *unlinked = try_rgrp_unlink(rgd, last_unlinked, |
1152 | ip->i_no_addr, &inode); | 1139 | ip->i_no_addr); |
1153 | if (!rg_locked) | 1140 | if (!rg_locked) |
1154 | gfs2_glock_dq_uninit(&al->al_rgd_gh); | 1141 | gfs2_glock_dq_uninit(&al->al_rgd_gh); |
1155 | if (inode) { | 1142 | if (*unlinked) |
1156 | if (error) { | 1143 | return -EAGAIN; |
1157 | if (inode->i_state & I_NEW) | ||
1158 | iget_failed(inode); | ||
1159 | else | ||
1160 | iput(inode); | ||
1161 | return ERR_PTR(error); | ||
1162 | } | ||
1163 | return inode; | ||
1164 | } | ||
1165 | if (error) | ||
1166 | return ERR_PTR(error); | ||
1167 | break; | 1144 | break; |
1168 | 1145 | ||
1169 | case GLR_TRYFAILED: | 1146 | case GLR_TRYFAILED: |
@@ -1171,7 +1148,7 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked) | |||
1171 | break; | 1148 | break; |
1172 | 1149 | ||
1173 | default: | 1150 | default: |
1174 | return ERR_PTR(error); | 1151 | return error; |
1175 | } | 1152 | } |
1176 | 1153 | ||
1177 | rgd = gfs2_rgrpd_get_next(rgd); | 1154 | rgd = gfs2_rgrpd_get_next(rgd); |
@@ -1180,7 +1157,7 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked) | |||
1180 | 1157 | ||
1181 | if (rgd == begin) { | 1158 | if (rgd == begin) { |
1182 | if (++loops >= 3) | 1159 | if (++loops >= 3) |
1183 | return ERR_PTR(-ENOSPC); | 1160 | return -ENOSPC; |
1184 | if (!skipped) | 1161 | if (!skipped) |
1185 | loops++; | 1162 | loops++; |
1186 | flags = 0; | 1163 | flags = 0; |
@@ -1200,7 +1177,7 @@ out: | |||
1200 | forward_rgrp_set(sdp, rgd); | 1177 | forward_rgrp_set(sdp, rgd); |
1201 | } | 1178 | } |
1202 | 1179 | ||
1203 | return NULL; | 1180 | return 0; |
1204 | } | 1181 | } |
1205 | 1182 | ||
1206 | /** | 1183 | /** |
@@ -1216,7 +1193,7 @@ int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line) | |||
1216 | struct gfs2_alloc *al = ip->i_alloc; | 1193 | struct gfs2_alloc *al = ip->i_alloc; |
1217 | struct inode *inode; | 1194 | struct inode *inode; |
1218 | int error = 0; | 1195 | int error = 0; |
1219 | u64 last_unlinked = NO_BLOCK; | 1196 | u64 last_unlinked = NO_BLOCK, unlinked; |
1220 | 1197 | ||
1221 | if (gfs2_assert_warn(sdp, al->al_requested)) | 1198 | if (gfs2_assert_warn(sdp, al->al_requested)) |
1222 | return -EINVAL; | 1199 | return -EINVAL; |
@@ -1232,14 +1209,19 @@ try_again: | |||
1232 | if (error) | 1209 | if (error) |
1233 | return error; | 1210 | return error; |
1234 | 1211 | ||
1235 | inode = get_local_rgrp(ip, &last_unlinked); | 1212 | error = get_local_rgrp(ip, &unlinked, &last_unlinked); |
1236 | if (inode) { | 1213 | if (error) { |
1237 | if (ip != GFS2_I(sdp->sd_rindex)) | 1214 | if (ip != GFS2_I(sdp->sd_rindex)) |
1238 | gfs2_glock_dq_uninit(&al->al_ri_gh); | 1215 | gfs2_glock_dq_uninit(&al->al_ri_gh); |
1239 | if (IS_ERR(inode)) | 1216 | if (error != -EAGAIN) |
1240 | return PTR_ERR(inode); | 1217 | return error; |
1241 | iput(inode); | 1218 | error = gfs2_unlinked_inode_lookup(ip->i_inode.i_sb, |
1219 | unlinked, &inode); | ||
1220 | if (inode) | ||
1221 | iput(inode); | ||
1242 | gfs2_log_flush(sdp, NULL); | 1222 | gfs2_log_flush(sdp, NULL); |
1223 | if (error == GLR_TRYFAILED) | ||
1224 | error = 0; | ||
1243 | goto try_again; | 1225 | goto try_again; |
1244 | } | 1226 | } |
1245 | 1227 | ||