Skip to content

Commit 2ca0c2f

Browse files
committed
gfs2: drain the ail2 list after io errors
Before this patch, gfs2_logd continually tried to flush its journal log, after the file system is withdrawn. We don't want to write anything to the journal, lest we add corruption. Best course of action is to drain the ail1 into the ail2 list (via gfs2_ail1_empty) then drain the ail2 list with a new function, ail2_drain. Signed-off-by: Bob Peterson <[email protected]> Reviewed-by: Andreas Gruenbacher <[email protected]>
1 parent b1676cb commit 2ca0c2f

File tree

2 files changed

+65
-10
lines changed

2 files changed

+65
-10
lines changed

fs/gfs2/log.c

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -299,20 +299,17 @@ static void gfs2_ail1_wait(struct gfs2_sbd *sdp)
299299
}
300300

301301
/**
302-
* gfs2_ail2_empty_one - Check whether or not a trans in the AIL has been synced
303-
* @sdp: the filesystem
304-
* @ai: the AIL entry
305-
*
302+
* gfs2_ail_empty_tr - empty one of the ail lists for a transaction
306303
*/
307304

308-
static void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
305+
static void gfs2_ail_empty_tr(struct gfs2_sbd *sdp, struct gfs2_trans *tr,
306+
struct list_head *head)
309307
{
310-
struct list_head *head = &tr->tr_ail2_list;
311308
struct gfs2_bufdata *bd;
312309

313310
while (!list_empty(head)) {
314-
bd = list_entry(head->prev, struct gfs2_bufdata,
315-
bd_ail_st_list);
311+
bd = list_first_entry(head, struct gfs2_bufdata,
312+
bd_ail_st_list);
316313
gfs2_assert(sdp, bd->bd_tr == tr);
317314
gfs2_remove_from_ail(bd);
318315
}
@@ -334,7 +331,7 @@ static void ail2_empty(struct gfs2_sbd *sdp, unsigned int new_tail)
334331
if (!rm)
335332
continue;
336333

337-
gfs2_ail2_empty_one(sdp, tr);
334+
gfs2_ail_empty_tr(sdp, tr, &tr->tr_ail2_list);
338335
list_del(&tr->tr_list);
339336
gfs2_assert_warn(sdp, list_empty(&tr->tr_ail1_list));
340337
gfs2_assert_warn(sdp, list_empty(&tr->tr_ail2_list));
@@ -801,6 +798,40 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags)
801798
log_pull_tail(sdp, tail);
802799
}
803800

801+
/**
802+
* ail_drain - drain the ail lists after a withdraw
803+
* @sdp: Pointer to GFS2 superblock
804+
*/
805+
static void ail_drain(struct gfs2_sbd *sdp)
806+
{
807+
struct gfs2_trans *tr;
808+
809+
spin_lock(&sdp->sd_ail_lock);
810+
/*
811+
* For transactions on the sd_ail1_list we need to drain both the
812+
* ail1 and ail2 lists. That's because function gfs2_ail1_start_one
813+
* (temporarily) moves items from its tr_ail1 list to tr_ail2 list
814+
* before revokes are sent for that block. Items on the sd_ail2_list
815+
* should have already gotten beyond that point, so no need.
816+
*/
817+
while (!list_empty(&sdp->sd_ail1_list)) {
818+
tr = list_first_entry(&sdp->sd_ail1_list, struct gfs2_trans,
819+
tr_list);
820+
gfs2_ail_empty_tr(sdp, tr, &tr->tr_ail1_list);
821+
gfs2_ail_empty_tr(sdp, tr, &tr->tr_ail2_list);
822+
list_del(&tr->tr_list);
823+
kfree(tr);
824+
}
825+
while (!list_empty(&sdp->sd_ail2_list)) {
826+
tr = list_first_entry(&sdp->sd_ail2_list, struct gfs2_trans,
827+
tr_list);
828+
gfs2_ail_empty_tr(sdp, tr, &tr->tr_ail2_list);
829+
list_del(&tr->tr_list);
830+
kfree(tr);
831+
}
832+
spin_unlock(&sdp->sd_ail_lock);
833+
}
834+
804835
/**
805836
* gfs2_log_flush - flush incore transaction(s)
806837
* @sdp: the filesystem
@@ -811,11 +842,18 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags)
811842

812843
void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
813844
{
814-
struct gfs2_trans *tr;
845+
struct gfs2_trans *tr = NULL;
815846
enum gfs2_freeze_state state = atomic_read(&sdp->sd_freeze_state);
816847

817848
down_write(&sdp->sd_log_flush_lock);
818849

850+
/*
851+
* Do this check while holding the log_flush_lock to prevent new
852+
* buffers from being added to the ail via gfs2_pin()
853+
*/
854+
if (gfs2_withdrawn(sdp))
855+
goto out;
856+
819857
/* Log might have been flushed while we waited for the flush lock */
820858
if (gl && !test_bit(GLF_LFLUSH, &gl->gl_flags)) {
821859
up_write(&sdp->sd_log_flush_lock);
@@ -843,8 +881,14 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
843881
sdp->sd_log_num_revoke == sdp->sd_log_committed_revoke);
844882

845883
gfs2_ordered_write(sdp);
884+
if (gfs2_withdrawn(sdp))
885+
goto out;
846886
lops_before_commit(sdp, tr);
887+
if (gfs2_withdrawn(sdp))
888+
goto out;
847889
gfs2_log_submit_bio(&sdp->sd_log_bio, REQ_OP_WRITE);
890+
if (gfs2_withdrawn(sdp))
891+
goto out;
848892

849893
if (sdp->sd_log_head != sdp->sd_log_flush_head) {
850894
log_flush_wait(sdp);
@@ -854,6 +898,8 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
854898
trace_gfs2_log_blocks(sdp, -1);
855899
log_write_header(sdp, flags);
856900
}
901+
if (gfs2_withdrawn(sdp))
902+
goto out;
857903
lops_after_commit(sdp, tr);
858904

859905
gfs2_log_lock(sdp);
@@ -892,6 +938,11 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
892938
}
893939

894940
out:
941+
if (gfs2_withdrawn(sdp)) {
942+
ail_drain(sdp); /* frees all transactions */
943+
tr = NULL;
944+
}
945+
895946
trace_gfs2_log_flush(sdp, 0, flags);
896947
up_write(&sdp->sd_log_flush_lock);
897948

fs/gfs2/trans.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,10 @@ void gfs2_trans_add_meta(struct gfs2_glock *gl, struct buffer_head *bh)
228228
fs_info(sdp, "GFS2:adding buf while frozen\n");
229229
gfs2_assert_withdraw(sdp, 0);
230230
}
231+
if (unlikely(gfs2_withdrawn(sdp))) {
232+
fs_info(sdp, "GFS2:adding buf while withdrawn! 0x%llx\n",
233+
(unsigned long long)bd->bd_bh->b_blocknr);
234+
}
231235
gfs2_pin(sdp, bd->bd_bh);
232236
mh->__pad0 = cpu_to_be64(0);
233237
mh->mh_jid = cpu_to_be32(sdp->sd_jdesc->jd_jid);

0 commit comments

Comments
 (0)