Skip to content

Commit bb47cce

Browse files
author
Andreas Gruenbacher
committed
gfs2: gfs2_log_flush withdraw fixes
When a withdraw occurs in gfs2_log_flush() and we are left with an unsubmitted bio, fail that bio. Otherwise, the bh's in that bio will remain locked and gfs2_evict_inode() -> truncate_inode_pages() -> gfs2_invalidate_folio() -> gfs2_discard() will hang trying to discard the locked bh's. In addition, when gfs2_log_flush() fails to submit a new transaction, unpin the buffers in the failing transaction like gfs2_remove_from_journal() does. If any of the bd's are on the ail2 list, leave them there and do_withdraw() -> gfs2_withdraw_glocks() -> inode_go_inval() -> truncate_inode_pages() -> gfs2_invalidate_folio() -> gfs2_discard() will remove them. They will be freed in gfs2_release_folio(). Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
1 parent fe2c8d0 commit bb47cce

1 file changed

Lines changed: 17 additions & 8 deletions

File tree

fs/gfs2/log.c

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -983,33 +983,38 @@ static void empty_ail1_list(struct gfs2_sbd *sdp)
983983
}
984984
}
985985

986-
static void gfs2_trans_drain_list(struct list_head *list)
986+
static void gfs2_trans_drain_list(struct gfs2_sbd *sdp, struct list_head *list)
987987
{
988988
struct gfs2_bufdata *bd;
989989

990990
while (!list_empty(list)) {
991991
bd = list_first_entry(list, struct gfs2_bufdata, bd_list);
992+
struct buffer_head *bh = bd->bd_bh;
993+
994+
WARN_ON_ONCE(!buffer_pinned(bh));
995+
clear_buffer_pinned(bh);
996+
trace_gfs2_pin(bd, 0);
997+
atomic_dec(&sdp->sd_log_pinned);
992998
list_del_init(&bd->bd_list);
993-
if (!list_empty(&bd->bd_ail_st_list))
994-
gfs2_remove_from_ail(bd);
995-
kmem_cache_free(gfs2_bufdata_cachep, bd);
999+
brelse(bh);
9961000
}
9971001
}
9981002

9991003
/**
10001004
* gfs2_trans_drain - drain the buf and databuf queue for a failed transaction
1005+
* @sdp: the filesystem
10011006
* @tr: the transaction to drain
10021007
*
10031008
* When this is called, we're taking an error exit for a log write that failed
10041009
* but since we bypassed the after_commit functions, we need to remove the
10051010
* items from the buf and databuf queue.
10061011
*/
1007-
static void gfs2_trans_drain(struct gfs2_trans *tr)
1012+
static void gfs2_trans_drain(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
10081013
{
10091014
if (!tr)
10101015
return;
1011-
gfs2_trans_drain_list(&tr->tr_buf);
1012-
gfs2_trans_drain_list(&tr->tr_databuf);
1016+
gfs2_trans_drain_list(sdp, &tr->tr_buf);
1017+
gfs2_trans_drain_list(sdp, &tr->tr_databuf);
10131018
}
10141019

10151020
void gfs2_remove_from_journal(struct buffer_head *bh, int meta)
@@ -1185,7 +1190,11 @@ static void __gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl,
11851190
return;
11861191

11871192
out_withdraw:
1188-
gfs2_trans_drain(tr);
1193+
if (sdp->sd_jdesc->jd_log_bio) {
1194+
bio_io_error(sdp->sd_jdesc->jd_log_bio);
1195+
sdp->sd_jdesc->jd_log_bio = NULL;
1196+
}
1197+
gfs2_trans_drain(sdp, tr);
11891198
/**
11901199
* If the tr_list is empty, we're withdrawing during a log
11911200
* flush that targets a transaction, but the transaction was

0 commit comments

Comments
 (0)