]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
xfs: fix memory leak in xfs_dqinode_metadir_create()
authorDawei Feng <dawei.feng@seu.edu.cn>
Sat, 27 Jun 2026 06:04:02 +0000 (14:04 +0800)
committerCarlos Maiolino <cem@kernel.org>
Wed, 1 Jul 2026 09:37:54 +0000 (11:37 +0200)
If xfs_metadir_create() fails in xfs_dqinode_metadir_create(), the current
code returns directly, leaking the allocated update and transaction state.
If the subsequent commit fails, the caller-owned inode reference is left
behind.

Fix this memory leak by routing the create failure path through
xfs_metadir_cancel().  For both create and commit failures, finish and
release any inode returned to the caller, mirroring the unwind pattern in
xfs_metadir_mkdir().

The bug was first flagged by an experimental analysis tool we are
developing for kernel memory-management bugs while analyzing
v6.13-rc1. The tool is still under development and is not yet publicly
available. Manual inspection confirms that the bug is still
present in v7.1.1.

An x86_64 allyesconfig build showed no new warnings. Runtime validation
used kprobe fault injection during `mount -o uquota` on a metadir XFS
image. Injecting xfs_metadir_create() reproduced the old active-update path
that left mount stuck later in mount setup; after this change, the same
injection reported cancel_hits=1 and irele_hits=1. Injecting
xfs_metadir_commit() exercised the old inode-reference leak path; after
this change, it reported irele_hits=1.

Fixes: e80fbe1ad8ef ("xfs: use metadir for quota inodes")
Cc: stable@vger.kernel.org # v6.13
Signed-off-by: Dawei Feng <dawei.feng@seu.edu.cn>
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
fs/xfs/libxfs/xfs_dquot_buf.c

index ce767b40482f8c9ecd4abe30d577a33609af0f2d..bbada0d3cc081fd83280d21538718aee00a3aa66 100644 (file)
@@ -436,17 +436,27 @@ xfs_dqinode_metadir_create(
 
        error = xfs_metadir_create(&upd, S_IFREG);
        if (error)
-               return error;
+               goto out_cancel;
 
        xfs_trans_log_inode(upd.tp, upd.ip, XFS_ILOG_CORE);
 
        error = xfs_metadir_commit(&upd);
        if (error)
-               return error;
+               goto out_irele;
 
        xfs_finish_inode_setup(upd.ip);
        *ipp = upd.ip;
        return 0;
+
+out_cancel:
+       xfs_metadir_cancel(&upd, error);
+out_irele:
+       /* Have to finish setting up the inode to ensure it's deleted. */
+       if (upd.ip) {
+               xfs_finish_inode_setup(upd.ip);
+               xfs_irele(upd.ip);
+       }
+       return error;
 }
 
 #ifndef __KERNEL__