Skip to content

Commit cc0581b

Browse files
AstralBobswhiteho
authored andcommitted
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 <[email protected]> Signed-off-by: Steven Whitehouse <[email protected]>
1 parent eaefbf9 commit cc0581b

File tree

1 file changed

+30
-48
lines changed

1 file changed

+30
-48
lines changed

fs/gfs2/rgrp.c

Lines changed: 30 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -952,16 +952,14 @@ static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_alloc *al)
952952
* The inode, if one has been found, in inode.
953953
*/
954954

955-
static int try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked,
956-
u64 skip, struct inode **inode)
955+
static u64 try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked,
956+
u64 skip)
957957
{
958958
u32 goal = 0, block;
959959
u64 no_addr;
960960
struct gfs2_sbd *sdp = rgd->rd_sbd;
961961
unsigned int n;
962-
int error = 0;
963962

964-
*inode = NULL;
965963
for(;;) {
966964
if (goal >= rgd->rd_data)
967965
break;
@@ -981,10 +979,7 @@ static int try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked,
981979
if (no_addr == skip)
982980
continue;
983981
*last_unlinked = no_addr;
984-
error = gfs2_unlinked_inode_lookup(rgd->rd_sbd->sd_vfs,
985-
no_addr, inode);
986-
if (*inode || error)
987-
return error;
982+
return no_addr;
988983
}
989984

990985
rgd->rd_flags &= ~GFS2_RDF_CHECK;
@@ -1069,11 +1064,12 @@ static void forward_rgrp_set(struct gfs2_sbd *sdp, struct gfs2_rgrpd *rgd)
10691064
* Try to acquire rgrp in way which avoids contending with others.
10701065
*
10711066
* Returns: errno
1067+
* unlinked: the block address of an unlinked block to be reclaimed
10721068
*/
10731069

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)
10751072
{
1076-
struct inode *inode = NULL;
10771073
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
10781074
struct gfs2_rgrpd *rgd, *begin = NULL;
10791075
struct gfs2_alloc *al = ip->i_alloc;
@@ -1082,6 +1078,7 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
10821078
int loops = 0;
10831079
int error, rg_locked;
10841080

1081+
*unlinked = 0;
10851082
rgd = gfs2_blk2rgrpd(sdp, ip->i_goal);
10861083

10871084
while (rgd) {
@@ -1103,29 +1100,19 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
11031100
because that would require an iput which can only
11041101
happen after the rgrp is unlocked. */
11051102
if (!rg_locked && rgd->rd_flags & GFS2_RDF_CHECK)
1106-
error = try_rgrp_unlink(rgd, last_unlinked,
1107-
ip->i_no_addr, &inode);
1103+
*unlinked = try_rgrp_unlink(rgd, last_unlinked,
1104+
ip->i_no_addr);
11081105
if (!rg_locked)
11091106
gfs2_glock_dq_uninit(&al->al_rgd_gh);
1110-
if (inode) {
1111-
if (error) {
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);
1107+
if (*unlinked)
1108+
return -EAGAIN;
11221109
/* fall through */
11231110
case GLR_TRYFAILED:
11241111
rgd = recent_rgrp_next(rgd);
11251112
break;
11261113

11271114
default:
1128-
return ERR_PTR(error);
1115+
return error;
11291116
}
11301117
}
11311118

@@ -1148,30 +1135,20 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
11481135
if (try_rgrp_fit(rgd, al))
11491136
goto out;
11501137
if (!rg_locked && rgd->rd_flags & GFS2_RDF_CHECK)
1151-
error = try_rgrp_unlink(rgd, last_unlinked,
1152-
ip->i_no_addr, &inode);
1138+
*unlinked = try_rgrp_unlink(rgd, last_unlinked,
1139+
ip->i_no_addr);
11531140
if (!rg_locked)
11541141
gfs2_glock_dq_uninit(&al->al_rgd_gh);
1155-
if (inode) {
1156-
if (error) {
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);
1142+
if (*unlinked)
1143+
return -EAGAIN;
11671144
break;
11681145

11691146
case GLR_TRYFAILED:
11701147
skipped++;
11711148
break;
11721149

11731150
default:
1174-
return ERR_PTR(error);
1151+
return error;
11751152
}
11761153

11771154
rgd = gfs2_rgrpd_get_next(rgd);
@@ -1180,7 +1157,7 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
11801157

11811158
if (rgd == begin) {
11821159
if (++loops >= 3)
1183-
return ERR_PTR(-ENOSPC);
1160+
return -ENOSPC;
11841161
if (!skipped)
11851162
loops++;
11861163
flags = 0;
@@ -1200,7 +1177,7 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
12001177
forward_rgrp_set(sdp, rgd);
12011178
}
12021179

1203-
return NULL;
1180+
return 0;
12041181
}
12051182

12061183
/**
@@ -1216,7 +1193,7 @@ int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line)
12161193
struct gfs2_alloc *al = ip->i_alloc;
12171194
struct inode *inode;
12181195
int error = 0;
1219-
u64 last_unlinked = NO_BLOCK;
1196+
u64 last_unlinked = NO_BLOCK, unlinked;
12201197

12211198
if (gfs2_assert_warn(sdp, al->al_requested))
12221199
return -EINVAL;
@@ -1232,14 +1209,19 @@ int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line)
12321209
if (error)
12331210
return error;
12341211

1235-
inode = get_local_rgrp(ip, &last_unlinked);
1236-
if (inode) {
1212+
error = get_local_rgrp(ip, &unlinked, &last_unlinked);
1213+
if (error) {
12371214
if (ip != GFS2_I(sdp->sd_rindex))
12381215
gfs2_glock_dq_uninit(&al->al_ri_gh);
1239-
if (IS_ERR(inode))
1240-
return PTR_ERR(inode);
1241-
iput(inode);
1216+
if (error != -EAGAIN)
1217+
return error;
1218+
error = gfs2_unlinked_inode_lookup(ip->i_inode.i_sb,
1219+
unlinked, &inode);
1220+
if (inode)
1221+
iput(inode);
12421222
gfs2_log_flush(sdp, NULL);
1223+
if (error == GLR_TRYFAILED)
1224+
error = 0;
12431225
goto try_again;
12441226
}
12451227

0 commit comments

Comments
 (0)