[PATCH RFC] ocfs2: fix circular locking dependency in ocfs2_dio_end_io_write()

"syzbot" <[email protected]>
Newsgroups dev.linux.lists.syzbot
Message-ID <[email protected]>
A circular locking dependency can occur involving three OCFS2 system inode
locks: INODE_ALLOC_SYSTEM_INODE, EXTENT_ALLOC_SYSTEM_INODE, and
ORPHAN_DIR_SYSTEM_INODE.

The circular dependency is formed by three separate code paths. First, in
ocfs2_mknod(), the code reserves an inode by acquiring the
INODE_ALLOC_SYSTEM_INODE lock, and then reserves metadata blocks by
acquiring the EXTENT_ALLOC_SYSTEM_INODE lock. Second, in
ocfs2_dio_end_io_write(), the code allocates metadata blocks for unwritten
extents, acquiring the EXTENT_ALLOC_SYSTEM_INODE lock. Later in the same
function, if the inode was orphaned, it calls
ocfs2_del_inode_from_orphan(), which acquires the ORPHAN_DIR_SYSTEM_INODE
lock. The allocation context is only freed at the end of the function,
meaning the EXTENT_ALLOC_SYSTEM_INODE lock is held while
ORPHAN_DIR_SYSTEM_INODE is acquired. Third, in ocfs2_wipe_inode(), the
ORPHAN_DIR_SYSTEM_INODE lock is acquired first to prevent races with
recovery completion, and then it calls ocfs2_remove_inode(), which acquires
the INODE_ALLOC_SYSTEM_INODE lock to free the inode.

This patch breaks the cycle by addressing the dependency in
ocfs2_dio_end_io_write(). The data_ac and meta_ac allocation contexts are
only needed for the transaction that marks the extents as written. Once the
transaction is committed and the allocation semaphore is released, these
contexts are no longer needed. We can safely free them, which releases the
EXTENT_ALLOC_SYSTEM_INODE lock, before calling
ocfs2_del_inode_from_orphan(). This ensures that the
EXTENT_ALLOC_SYSTEM_INODE lock is dropped before we attempt to acquire the
ORPHAN_DIR_SYSTEM_INODE lock, successfully breaking the circular
dependency.

Fixes: d647c5b2fbf8 ("ocfs2: split transactions in dio completion to avoid credit exhaustion")
Assisted-by: Gemini:gemini-3.1-pro-preview syzbot
Reported-by: [email protected]
Closes: https://syzkaller.appspot.com/bug?extid=b225d4dfce6219600c42
Link: https://syzkaller.appspot.com/ai_job?id=c86e9953-fff6-40ca-b2f0-eff12366a33a
To: "Joel Becker" <[email protected]>
To: "Joseph Qi" <[email protected]>
To: "Mark Fasheh" <[email protected]>
To: <[email protected]>
Cc: <[email protected]>

---
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index 6ec198bda..4acdbb708 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -2372,6 +2372,15 @@ static int ocfs2_dio_end_io_write(struct inode *inode,
 unlock:
 	up_write(&oi->ip_alloc_sem);
 
+	if (data_ac) {
+		ocfs2_free_alloc_context(data_ac);
+		data_ac = NULL;
+	}
+	if (meta_ac) {
+		ocfs2_free_alloc_context(meta_ac);
+		meta_ac = NULL;
+	}
+
 	/* everything looks good, let's start the cleanup */
 	if (!ret && dwc->dw_orphaned) {
 		BUG_ON(dwc->dw_writer_pid != task_pid_nr(current));
@@ -2383,10 +2392,6 @@ static int ocfs2_dio_end_io_write(struct inode *inode,
 	ocfs2_inode_unlock(inode, 1);
 	brelse(di_bh);
 out:
-	if (data_ac)
-		ocfs2_free_alloc_context(data_ac);
-	if (meta_ac)
-		ocfs2_free_alloc_context(meta_ac);
 	ocfs2_run_deallocs(osb, &dealloc);
 	ocfs2_dio_free_write_ctx(inode, dwc);
 


base-commit: e7ae89a0c97ce2b68b0983cd01eda67cf373517d
-- 
This is an AI-generated patch subject to moderation.
Reply with '#syz upstream' to Sign-off the patch as a human author
and send it to the upstream kernel mailing lists.
Reply with '#syz reject' to reject it ('#syz unreject' to undo).

See https://goo.gle/syzbot-ai-patches for information about AI-generated patches.
You can comment on the patch as usual, syzbot will try to address
the comments and send a new version of the patch if necessary.
syzbot engineers can be reached at [email protected].
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.