gfs2: log error reform
authorBob Peterson <rpeterso@redhat.com>
Wed, 10 Apr 2019 17:46:35 +0000 (11:46 -0600)
committerBob Peterson <rpeterso@redhat.com>
Mon, 10 Feb 2020 13:39:49 +0000 (07:39 -0600)
Before this patch, gfs2 kept track of journal io errors in two
places sd_log_error and the SDF_AIL1_IO_ERROR flag in sd_flags.
This patch consolidates the two into sd_log_error so that it
reflects the first error encountered writing to the journal.
In future patches, we will take advantage of this by checking
this value rather than having to check both when reacting to
io errors.

In addition, this fixes a tight loop in unmount: If buffers
get on the ail1 list and an io error occurs elsewhere, the
ail1 list would never be cleared because they were always busy.
So unmount would hang, waiting for the ail1 list to empty.

Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Reviewed-by: Andreas Gruenbacher <agruenba@redhat.com>
fs/gfs2/incore.h
fs/gfs2/log.c
fs/gfs2/quota.c

index b95c8a31d309462f42a3239b9f3c23d6046dc329..ab89f746b3b6c74ae13c2a8132f1fca824c9ae5e 100644 (file)
@@ -615,9 +615,8 @@ enum {
        SDF_RORECOVERY          = 7, /* read only recovery */
        SDF_SKIP_DLM_UNLOCK     = 8,
        SDF_FORCE_AIL_FLUSH     = 9,
-       SDF_AIL1_IO_ERROR       = 10,
-       SDF_FS_FROZEN           = 11,
-       SDF_WITHDRAWING         = 12, /* Will withdraw eventually */
+       SDF_FS_FROZEN           = 10,
+       SDF_WITHDRAWING         = 11, /* Will withdraw eventually */
 };
 
 enum gfs2_freeze_state {
@@ -828,7 +827,7 @@ struct gfs2_sbd {
        atomic_t sd_log_in_flight;
        struct bio *sd_log_bio;
        wait_queue_head_t sd_log_flush_wait;
-       int sd_log_error;
+       int sd_log_error; /* First log error */
 
        atomic_t sd_reserving_log;
        wait_queue_head_t sd_reserving_log_wait;
index 9ebec6f93fa33a22fcc37b259497758f90e86506..584bb7ce15bf53e14f18afc9070e58b23f615b9d 100644 (file)
@@ -108,8 +108,7 @@ __acquires(&sdp->sd_ail_lock)
                                          &tr->tr_ail2_list);
                                continue;
                        }
-                       if (!test_and_set_bit(SDF_AIL1_IO_ERROR,
-                                             &sdp->sd_flags)) {
+                       if (!cmpxchg(&sdp->sd_log_error, 0, -EIO)) {
                                gfs2_io_error_bh(sdp, bh);
                                gfs2_withdraw_delayed(sdp);
                        }
@@ -205,10 +204,19 @@ static void gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
                                         bd_ail_st_list) {
                bh = bd->bd_bh;
                gfs2_assert(sdp, bd->bd_tr == tr);
-               if (buffer_busy(bh))
+               /*
+                * If another process flagged an io error, e.g. writing to the
+                * journal, error all other bhs and move them off the ail1 to
+                * prevent a tight loop when unmount tries to flush ail1,
+                * regardless of whether they're still busy. If no outside
+                * errors were found and the buffer is busy, move to the next.
+                * If the ail buffer is not busy and caught an error, flag it
+                * for others.
+                */
+               if (!sdp->sd_log_error && buffer_busy(bh))
                        continue;
                if (!buffer_uptodate(bh) &&
-                   !test_and_set_bit(SDF_AIL1_IO_ERROR, &sdp->sd_flags)) {
+                   !cmpxchg(&sdp->sd_log_error, 0, -EIO)) {
                        gfs2_io_error_bh(sdp, bh);
                        gfs2_withdraw_delayed(sdp);
                }
index e9f93045eb01cff843ec1ea876726579b35fc9b5..ca2194cfa38ecbbdc6ffa3ea7ca72f279c171053 100644 (file)
@@ -1477,7 +1477,7 @@ static void quotad_error(struct gfs2_sbd *sdp, const char *msg, int error)
                return;
        if (!gfs2_withdrawn(sdp)) {
                fs_err(sdp, "gfs2_quotad: %s error %d\n", msg, error);
-               sdp->sd_log_error = error;
+               cmpxchg(&sdp->sd_log_error, 0, error);
                wake_up(&sdp->sd_logd_waitq);
        }
 }