All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/1] ext4: drop extra ea_inode ref in cached-block reuse path
@ 2026-08-12  4:45 Matthias Goergens
  2026-08-12  5:05 ` sashiko-bot
  0 siblings, 1 reply; 2+ messages in thread
From: Matthias Goergens @ 2026-08-12  4:45 UTC (permalink / raw)
  To: linux-ext4; +Cc: tytso, jack, Matthias Goergens

ext4_xattr_block_set() acquires a reference to the ea_inode via
ext4_xattr_inode_lookup_create() before constructing the new xattr
block.  In the new-block allocation path this extra reference is dropped
after ext4_xattr_inode_inc_ref_all() accounts for every entry in the
block.  But when mbcache supplies an identical existing block and that
block is reused, the cached block already carries the correct refcount
for its entries, and the extra reference is never dropped.

The cleanup block at the end of the function only calls
ext4_xattr_inode_dec_ref() when error is non-zero, so the success path
through cache reuse leaks one refcount.  Each reuse event adds another;
eventually the saturated refcount prevents the ea_inode from being freed
when its last real reference is dropped.

Add the matching drop when the entry was not written directly to the old
physical buffer (bs->bh && s->base == bs->bh->b_data).  In that case the
reference belongs to the old buffer, which the later release_block()
handles.  When s->base is a clone or a fresh allocation and is discarded
in favour of the cached block, the extra reference must be dropped.

Found by the Sashiko AI review bot while reviewing the xattr
saturation-livelock fix.

Fixes: 0a46ef234756 ("ext4: do not create EA inode under buffer lock")
---
 fs/ext4/xattr.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index 982a1f831e228..cf26932a528b9 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -2107,6 +2107,26 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
 			mb_cache_entry_touch(ea_block_cache, ce);
 			mb_cache_entry_put(ea_block_cache, ce);
 			ce = NULL;
+			if (!(bs->bh && s->base == bs->bh->b_data) &&
+			    ea_inode) {
+				/*
+				 * The reused cached block already holds a
+				 * reference to the ea_inode.  Drop the extra
+				 * reference from
+				 * ext4_xattr_inode_lookup_create() unless the
+				 * entry was written directly to the old
+				 * physical buffer, in which case the reference
+				 * belongs to that buffer.
+				 */
+				error = ext4_xattr_inode_dec_ref(handle,
+								 ea_inode);
+				if (error)
+					ext4_warning_inode(ea_inode,
+							   "dec ref error=%d",
+							   error);
+				iput(ea_inode);
+				ea_inode = NULL;
+			}
 		} else if (bs->bh && s->base == bs->bh->b_data) {
 			/* We were modifying this block in-place. */
 			ea_bdebug(bs->bh, "keeping this block");
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-08-12  5:05 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-12  4:45 [PATCH 1/1] ext4: drop extra ea_inode ref in cached-block reuse path Matthias Goergens
2026-08-12  5:05 ` sashiko-bot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.