]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
gfs2: clear ail1 list when gfs2 withdraws
authorBob Peterson <rpeterso@redhat.com>
Wed, 13 Nov 2019 17:47:09 +0000 (11:47 -0600)
committerBob Peterson <rpeterso@redhat.com>
Mon, 10 Feb 2020 13:39:48 +0000 (07:39 -0600)
This patch fixes a bug in which function gfs2_log_flush can get into
an infinite loop when a gfs2 file system is withdrawn. The problem
is the infinite loop "for (;;)" in gfs2_log_flush which would never
finish because the io error and subsequent withdraw prevented the
items from being taken off the ail list.

This patch tries to clean up the mess by allowing withdraw situations
to move not-in-flight buffer_heads to the ail2 list, where they will
be dealt with later.

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

index d1ab04135b2f6822582d577f019104a0c265a83b..9ebec6f93fa33a22fcc37b259497758f90e86506 100644 (file)
@@ -103,16 +103,22 @@ __acquires(&sdp->sd_ail_lock)
                gfs2_assert(sdp, bd->bd_tr == tr);
 
                if (!buffer_busy(bh)) {
-                       if (!buffer_uptodate(bh) &&
-                           !test_and_set_bit(SDF_AIL1_IO_ERROR,
+                       if (buffer_uptodate(bh)) {
+                               list_move(&bd->bd_ail_st_list,
+                                         &tr->tr_ail2_list);
+                               continue;
+                       }
+                       if (!test_and_set_bit(SDF_AIL1_IO_ERROR,
                                              &sdp->sd_flags)) {
                                gfs2_io_error_bh(sdp, bh);
                                gfs2_withdraw_delayed(sdp);
                        }
-                       list_move(&bd->bd_ail_st_list, &tr->tr_ail2_list);
-                       continue;
                }
 
+               if (gfs2_withdrawn(sdp)) {
+                       gfs2_remove_from_ail(bd);
+                       continue;
+               }
                if (!buffer_dirty(bh))
                        continue;
                if (gl == bd->bd_gl)
@@ -859,6 +865,8 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
                                if (gfs2_ail1_empty(sdp))
                                        break;
                        }
+                       if (gfs2_withdrawn(sdp))
+                               goto out;
                        atomic_dec(&sdp->sd_log_blks_free); /* Adjust for unreserved buffer */
                        trace_gfs2_log_blocks(sdp, -1);
                        log_write_header(sdp, flags);
@@ -871,6 +879,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
                        atomic_set(&sdp->sd_freeze_state, SFS_FROZEN);
        }
 
+out:
        trace_gfs2_log_flush(sdp, 0, flags);
        up_write(&sdp->sd_log_flush_lock);