]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
gfs2: Don't start unnecessary transactions during log flush
authorAndreas Gruenbacher <agruenba@redhat.com>
Fri, 28 Mar 2025 21:47:02 +0000 (22:47 +0100)
committerAndreas Gruenbacher <agruenba@redhat.com>
Thu, 22 May 2025 07:12:27 +0000 (09:12 +0200)
Commit 8d391972ae2d ("gfs2: Remove __gfs2_writepage()") changed the log
flush code in gfs2_ail1_start_one() to call aops->writepages() instead
of aops->writepage().  For jdata inodes, this means that we will now try
to reserve log space and start a transaction before we can determine
that the pages in question have already been journaled.  When this
happens in the context of gfs2_logd(), it can now appear that not enough
log space is available for freeing up log space, and we will lock up.

Fix that by issuing journal writes directly instead of going through
aops->writepages() in the log flush code.

Fixes: 8d391972ae2d ("gfs2: Remove __gfs2_writepage()")
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
fs/gfs2/aops.c
fs/gfs2/aops.h
fs/gfs2/log.c

index 1a3a420316fab04e1715b65d261c6624f41e38f0..14f204cd5a82fff94dd98483bf5f7cb163925608 100644 (file)
@@ -117,6 +117,37 @@ static int __gfs2_jdata_write_folio(struct folio *folio,
        return gfs2_write_jdata_folio(folio, wbc);
 }
 
+/**
+ * gfs2_jdata_writeback - Write jdata folios to the log
+ * @mapping: The mapping to write
+ * @wbc: The writeback control
+ *
+ * Returns: errno
+ */
+int gfs2_jdata_writeback(struct address_space *mapping, struct writeback_control *wbc)
+{
+       struct inode *inode = mapping->host;
+       struct gfs2_inode *ip = GFS2_I(inode);
+       struct gfs2_sbd *sdp = GFS2_SB(mapping->host);
+       struct folio *folio = NULL;
+       int error;
+
+       BUG_ON(current->journal_info);
+       if (gfs2_assert_withdraw(sdp, ip->i_gl->gl_state == LM_ST_EXCLUSIVE))
+               return 0;
+
+       while ((folio = writeback_iter(mapping, wbc, folio, &error))) {
+               if (folio_test_checked(folio)) {
+                       folio_redirty_for_writepage(wbc, folio);
+                       folio_unlock(folio);
+                       continue;
+               }
+               error = __gfs2_jdata_write_folio(folio, wbc);
+       }
+
+       return error;
+}
+
 /**
  * gfs2_writepages - Write a bunch of dirty pages back to disk
  * @mapping: The mapping to write
index f9fa41aaeaf410d91c8ed1012faf1c351de4df62..bf002522a782206f9d8e43cfee048ce5aed50b64 100644 (file)
@@ -9,5 +9,6 @@
 #include "incore.h"
 
 void adjust_fs_space(struct inode *inode);
+int gfs2_jdata_writeback(struct address_space *mapping, struct writeback_control *wbc);
 
 #endif /* __AOPS_DOT_H__ */
index f9c5089783d24c605e1e7d16777be663b4e26172..115c4ac457e90a5031254cc8207c69cd65f8307c 100644 (file)
@@ -31,6 +31,7 @@
 #include "dir.h"
 #include "trace_gfs2.h"
 #include "trans.h"
+#include "aops.h"
 
 static void gfs2_log_shutdown(struct gfs2_sbd *sdp);
 
@@ -131,7 +132,11 @@ __acquires(&sdp->sd_ail_lock)
                if (!mapping)
                        continue;
                spin_unlock(&sdp->sd_ail_lock);
-               ret = mapping->a_ops->writepages(mapping, wbc);
+               BUG_ON(GFS2_SB(mapping->host) != sdp);
+               if (gfs2_is_jdata(GFS2_I(mapping->host)))
+                       ret = gfs2_jdata_writeback(mapping, wbc);
+               else
+                       ret = mapping->a_ops->writepages(mapping, wbc);
                if (need_resched()) {
                        blk_finish_plug(plug);
                        cond_resched();