From: Deepanshu Kartikey <kartikey406@gmail.com>
To: mark@fasheh.com, jlbec@evilplan.org, joseph.qi@linux.alibaba.com,
bigeasy@linutronix.de, clrkwllms@kernel.org, rostedt@goodmis.org
Cc: ocfs2-devel@lists.linux.dev, linux-kernel@vger.kernel.org,
linux-rt-devel@lists.linux.dev,
Deepanshu Kartikey <kartikey406@gmail.com>,
syzbot+ce129763ce7d7e914739@syzkaller.appspotmail.com
Subject: [PATCH] ocfs2: fix deadlock in dio write orphan cleanup path
Date: Sat, 20 Jun 2026 13:38:02 +0530 [thread overview]
Message-ID: <20260620080802.35165-1-kartikey406@gmail.com> (raw)
PREEMPT_RT's rtmutex PI chain walker detected a lock dependency
cycle in a single thread:
ocfs2_file_write_iter()
inode_lock(file_inode) [Lock A]
ocfs2_dio_end_io_write()
ocfs2_inode_lock() [Lock B]
ocfs2_del_inode_from_orphan()
inode_lock(orphan_dir) [Lock D] <- cycle detected!
The problem is lock ordering. Lock B is held when Lock D is
acquired. Recovery paths acquire these locks in a different
order creating a potential cycle in the lock dependency graph.
Fix this by releasing Lock B (ocfs2_inode_unlock + brelse(di_bh))
BEFORE calling ocfs2_del_inode_from_orphan(). Pass NULL for di_bh
to signal that ocfs2_del_inode_from_orphan() should acquire its
own fresh cluster lock and di_bh internally.
This ensures consistent lock ordering:
Before: B held -> D acquired (inconsistent)
After: B released -> B' fresh -> D (consistent)
Reported-by: syzbot+ce129763ce7d7e914739@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=ce129763ce7d7e914739
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
fs/ocfs2/aops.c | 21 +++++++++++++++------
fs/ocfs2/namei.c | 17 ++++++++++++++++-
2 files changed, 31 insertions(+), 7 deletions(-)
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index 6ec198bdab12..15b059a23ebc 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -2280,6 +2280,7 @@ static int ocfs2_dio_end_io_write(struct inode *inode,
handle_t *handle = NULL;
loff_t end = offset + bytes;
int ret = 0, credits = 0, batch = 0;
+ bool orphaned = false;
ocfs2_init_dealloc_ctxt(&dealloc);
@@ -2371,17 +2372,25 @@ static int ocfs2_dio_end_io_write(struct inode *inode,
ocfs2_commit_trans(osb, handle);
unlock:
up_write(&oi->ip_alloc_sem);
+ /*
+ * Release the cluster lock and di_bh BEFORE calling
+ * ocfs2_del_inode_from_orphan(). That function will acquire
+ * inode_lock(orphan_dir_inode) which would cause an AB-BA
+ * deadlock with recovery paths that hold orphan_dir lock
+ * before acquiring the file inode lock.
+ */
+ orphaned = (!ret && dwc->dw_orphaned);
+ ocfs2_inode_unlock(inode, 1);
+ brelse(di_bh);
+ di_bh = NULL;
- /* everything looks good, let's start the cleanup */
- if (!ret && dwc->dw_orphaned) {
+ /* everything looks good, let's start the orphan cleanup */
+ if (orphaned) {
BUG_ON(dwc->dw_writer_pid != task_pid_nr(current));
-
- ret = ocfs2_del_inode_from_orphan(osb, inode, di_bh, 0, 0);
+ ret = ocfs2_del_inode_from_orphan(osb, inode, NULL, 0, 0);
if (ret < 0)
mlog_errno(ret);
}
- ocfs2_inode_unlock(inode, 1);
- brelse(di_bh);
out:
if (data_ac)
ocfs2_free_alloc_context(data_ac);
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index 1277666c77cd..25bbe2a9776e 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -2712,10 +2712,21 @@ int ocfs2_del_inode_from_orphan(struct ocfs2_super *osb,
{
struct inode *orphan_dir_inode = NULL;
struct buffer_head *orphan_dir_bh = NULL;
- struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+ struct ocfs2_dinode *di;
handle_t *handle = NULL;
int status = 0;
+ struct buffer_head *local_di_bh = NULL;
+ if (!di_bh) {
+ status = ocfs2_inode_lock(inode, &local_di_bh, 1);
+ if (status < 0) {
+ mlog_errno(status);
+ return status;
+ }
+ di_bh = local_di_bh;
+ }
+
+ di = (struct ocfs2_dinode *)di_bh->b_data;
orphan_dir_inode = ocfs2_get_system_file_inode(osb,
ORPHAN_DIR_SYSTEM_INODE,
le16_to_cpu(di->i_dio_orphaned_slot));
@@ -2779,6 +2790,10 @@ int ocfs2_del_inode_from_orphan(struct ocfs2_super *osb,
iput(orphan_dir_inode);
bail:
+ if (local_di_bh) {
+ ocfs2_inode_unlock(inode, 1);
+ brelse(local_di_bh);
+ }
return status;
}
--
2.43.0
next reply other threads:[~2026-06-20 8:08 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-20 8:08 Deepanshu Kartikey [this message]
2026-06-20 8:20 ` [PATCH] ocfs2: fix deadlock in dio write orphan cleanup path sashiko-bot
2026-06-20 17:59 ` Matthew Wilcox
2026-06-20 23:26 ` Deepanshu Kartikey
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260620080802.35165-1-kartikey406@gmail.com \
--to=kartikey406@gmail.com \
--cc=bigeasy@linutronix.de \
--cc=clrkwllms@kernel.org \
--cc=jlbec@evilplan.org \
--cc=joseph.qi@linux.alibaba.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-rt-devel@lists.linux.dev \
--cc=mark@fasheh.com \
--cc=ocfs2-devel@lists.linux.dev \
--cc=rostedt@goodmis.org \
--cc=syzbot+ce129763ce7d7e914739@syzkaller.appspotmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.