summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruenba@redhat.com>2025-11-11 00:18:44 +0300
committerAndreas Gruenbacher <agruenba@redhat.com>2026-03-23 22:55:24 +0300
commite2de65130d6ce599cfc114c515665194fe2dbf1d (patch)
tree295c9c40d53bc96c362f98c96febd1f8a40777af
parent0ac82bc7b7922add7f92d85732b4531af55c1e90 (diff)
downloadlinux-e2de65130d6ce599cfc114c515665194fe2dbf1d.tar.xz
gfs2: Avoid unnecessary transactions in evict_linked_inode
In evict_linked_inode(), the truncate_inode_pages() calls are carried out inside a transaction. This code was added to what was then function gfs2_delete_inode() in commit 16615be18cadf ("[GFS2] Clean up journaled data writing"). These transactions are only used for creating revokes for the jdata buffers in the journal, so don't create such transactions when we know that the address space doesn't contain any jdata buffers for this inode and truncate the metadata address space outside of the transaction. Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
-rw-r--r--fs/gfs2/super.c35
1 files changed, 30 insertions, 5 deletions
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index fd8eb9e15719..9149fa375ef3 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -1324,6 +1324,35 @@ out:
return ret;
}
+static int gfs2_truncate_inode_pages(struct inode *inode)
+{
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_sbd *sdp = GFS2_SB(inode);
+ struct address_space *mapping = &inode->i_data;
+ bool need_trans = gfs2_is_jdata(ip) && mapping->nrpages;
+ int ret;
+
+ /*
+ * Truncating a jdata inode address space may create revokes in
+ * truncate_inode_pages() -> gfs2_invalidate_folio() -> ... ->
+ * gfs2_remove_from_journal(), so we need a transaction here.
+ *
+ * FIXME: During a withdraw, no new transactions can be created.
+ * In that case, we skip the truncate, but that doesn't help because
+ * truncate_inode_pages_final() will then call gfs2_invalidate_folio()
+ * again, and outside of a transaction.
+ */
+ if (need_trans) {
+ ret = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks);
+ if (ret)
+ return ret;
+ }
+ truncate_inode_pages(mapping, 0);
+ if (need_trans)
+ gfs2_trans_end(sdp);
+ return 0;
+}
+
/*
* evict_linked_inode - evict an inode whose dinode has not been unlinked
* @inode: The inode to evict
@@ -1346,14 +1375,10 @@ static int evict_linked_inode(struct inode *inode)
write_inode_now(inode, 1);
gfs2_ail_flush(ip->i_gl, 0);
- ret = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks);
+ ret = gfs2_truncate_inode_pages(inode);
if (ret)
return ret;
-
- /* Needs to be done before glock release & also in a transaction */
- truncate_inode_pages(&inode->i_data, 0);
truncate_inode_pages(metamapping, 0);
- gfs2_trans_end(sdp);
return 0;
}