]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
gfs2: add some missing log locking
authorAndreas Gruenbacher <agruenba@redhat.com>
Tue, 31 Mar 2026 04:13:42 +0000 (06:13 +0200)
committerAndreas Gruenbacher <agruenba@redhat.com>
Tue, 7 Apr 2026 20:20:00 +0000 (22:20 +0200)
Function gfs2_logd() calls the log flushing functions gfs2_ail1_start(),
gfs2_ail1_wait(), and gfs2_ail1_empty() without holding sdp->sd_log_flush_lock,
but these functions require exclusion against concurrent transactions.

To fix that, add a non-locking __gfs2_log_flush() function.  Then, in
gfs2_logd(), take sdp->sd_log_flush_lock before calling the above mentioned log
flushing functions and __gfs2_log_flush().

Fixes: 5e4c7632aae1c ("gfs2: Issue revokes more intelligently")
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
fs/gfs2/log.c

index 31ee7a0e86a261c77ff963970501d87aef6937fc..a96f9b9331e8045c419dc6fa6c993191afca2654 100644 (file)
@@ -1053,14 +1053,15 @@ void gfs2_remove_from_journal(struct buffer_head *bh, int meta)
 }
 
 /**
- * gfs2_log_flush - flush incore transaction(s)
+ * __gfs2_log_flush - flush incore transaction(s)
  * @sdp: The filesystem
  * @gl: The glock structure to flush.  If NULL, flush the whole incore log
  * @flags: The log header flags: GFS2_LOG_HEAD_FLUSH_* and debug flags
  *
  */
 
-void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
+static void __gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl,
+                            u32 flags)
 {
        struct gfs2_trans *tr = NULL;
        unsigned int reserved_blocks = 0, used_blocks = 0;
@@ -1068,7 +1069,6 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
        unsigned int first_log_head;
        unsigned int reserved_revokes = 0;
 
-       down_write(&sdp->sd_log_flush_lock);
        trace_gfs2_log_flush(sdp, 1, flags);
 
 repeat:
@@ -1180,7 +1180,6 @@ out:
                gfs2_assert_withdraw(sdp, used_blocks < reserved_blocks);
                gfs2_log_release(sdp, reserved_blocks - used_blocks);
        }
-       up_write(&sdp->sd_log_flush_lock);
        gfs2_trans_free(sdp, tr);
        trace_gfs2_log_flush(sdp, 0, flags);
        return;
@@ -1201,6 +1200,13 @@ out_withdraw:
        goto out_end;
 }
 
+void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
+{
+       down_write(&sdp->sd_log_flush_lock);
+       __gfs2_log_flush(sdp, gl, flags);
+       up_write(&sdp->sd_log_flush_lock);
+}
+
 /**
  * gfs2_merge_trans - Merge a new transaction into a cached transaction
  * @sdp: the filesystem
@@ -1332,19 +1338,25 @@ int gfs2_logd(void *data)
                        break;
 
                if (gfs2_jrnl_flush_reqd(sdp) || t == 0) {
+                       down_write(&sdp->sd_log_flush_lock);
                        gfs2_ail1_empty(sdp, 0);
-                       gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL |
-                                                 GFS2_LFC_LOGD_JFLUSH_REQD);
+                       __gfs2_log_flush(sdp, NULL,
+                                        GFS2_LOG_HEAD_FLUSH_NORMAL |
+                                        GFS2_LFC_LOGD_JFLUSH_REQD);
+                       up_write(&sdp->sd_log_flush_lock);
                }
 
                if (test_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags) ||
                    gfs2_ail_flush_reqd(sdp)) {
                        clear_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags);
+                       down_write(&sdp->sd_log_flush_lock);
                        gfs2_ail1_start(sdp);
                        gfs2_ail1_wait(sdp);
                        gfs2_ail1_empty(sdp, 0);
-                       gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL |
-                                                 GFS2_LFC_LOGD_AIL_FLUSH_REQD);
+                       __gfs2_log_flush(sdp, NULL,
+                                        GFS2_LOG_HEAD_FLUSH_NORMAL |
+                                        GFS2_LFC_LOGD_AIL_FLUSH_REQD);
+                       up_write(&sdp->sd_log_flush_lock);
                }
 
                t = gfs2_tune_get(sdp, gt_logd_secs) * HZ;