mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: ThangNN99 <ngocthang2710.1999@gmail.com>
To: tytso@mit.edu
Cc: Jan Kara <jack@suse.cz>,
	adilger.kernel@dilger.ca, libaokun@linux.alibaba.com,
	ojaswin@linux.ibm.com, ritesh.list@gmail.com,
	yi.zhang@huawei.com, linux-ext4@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	ThangNN99 <ngocthang2710.1999@gmail.com>,
	syzbot+03afbb29537f0336b7ad@syzkaller.appspotmail.com
Subject: [PATCH v2 v2] ext4: avoid buffer/folio lock inversion in __ext4_get_inode_loc()
Date: Mon,  7 Sep 2026 22:50:17 +0700	[thread overview]
Message-ID: <20260907155017.75543-1-ngocthang2710.1999@gmail.com> (raw)
In-Reply-To: <20260906104841.56075-1-ngocthang2710.1999@gmail.com>

__ext4_get_inode_loc() looks up the inode bitmap bh while holding the
lock on the inode table bh:

  __ext4_get_inode_loc()
    lock_buffer(itable block)
    sb_getblk(inode bitmap block)
      __find_get_block_nonatomic()
        folio_lock(bdev folio for bitmap block)

whereas block_read_full_folio() (e.g. userspace reading the bdev inode
directly) takes the same two locks in the opposite order:

  block_read_full_folio()
    folio_lock(some folio)
      lock_buffer(bh in folio)

With blocksize == foliosize this can't overlap, but once foliosize >
blocksize the inode table block can land in the same folio as the
inode bitmap block, and the two orders deadlock on each other's lock.
Use the non-blocking cache lookup for the bitmap probe instead; a miss
already falls back to make_io exactly as before.

Only ext4_reserve_inode_write() reaches this probe with a real inode
(ext4_iget() passes NULL, which skips it), and it normally runs right
after the read that loaded that same inode, so the itable buffer is
still warm and the early "already uptodate" return skips the probe.
The window needs the folio reclaimed between load and writeback, which
is why this is rare and why syzbot's bisection could not pin it down.

Reproduction status: root-caused from source and confirmed against
both syzbot stacks (inode.c:__ext4_get_inode_loc vs.
buffer.c:block_read_full_folio); the lock_buffer()/reserve_inode_write
path was exercised live (orphan cleanup on mount) to confirm reachability
and to confirm this patch introduces no regression there. The deadlock
itself was not reproduced locally -- doing so needs the itable buffer
genuinely reclaimed between inode load and writeback, which a small
single-shot QEMU test doesn't naturally produce.

Reported-by: syzbot+03afbb29537f0336b7ad@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=03afbb29537f0336b7ad
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: ThangNN99 <ngocthang2710.1999@gmail.com>
Assisted-by: LLM
---
 fs/ext4/inode.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index bd4b778df9eb..13e3cb829461 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -4942,8 +4942,12 @@ static int __ext4_get_inode_loc(struct super_block *sb, unsigned long ino,
 
 		start = inode_offset & ~(inodes_per_block - 1);
 
-		/* Is the inode bitmap in cache? */
-		bitmap_bh = sb_getblk(sb, ext4_inode_bitmap(sb, gdp));
+		/*
+		 * Is the inode bitmap in cache? Non-blocking lookup: bh above
+		 * is locked, and blocking here would folio_lock() against a
+		 * block_read_full_folio() that locks bh the other way round.
+		 */
+		bitmap_bh = sb_find_get_block(sb, ext4_inode_bitmap(sb, gdp));
 		if (unlikely(!bitmap_bh))
 			goto make_io;
 
-- 
2.43.0


  parent reply	other threads:[~2026-09-07 15:50 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-06 10:48 [PATCH] " ThangNN99
2026-09-07  9:15 ` Jan Kara
2026-09-07 15:50 ` ThangNN99
2026-09-07 15:50 ` ThangNN99 [this message]
2026-09-11 17:02   ` [PATCH v2] " Nguyen Ngoc Thang

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=20260907155017.75543-1-ngocthang2710.1999@gmail.com \
    --to=ngocthang2710.1999@gmail.com \
    --cc=adilger.kernel@dilger.ca \
    --cc=jack@suse.cz \
    --cc=libaokun@linux.alibaba.com \
    --cc=linux-ext4@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=ojaswin@linux.ibm.com \
    --cc=ritesh.list@gmail.com \
    --cc=syzbot+03afbb29537f0336b7ad@syzkaller.appspotmail.com \
    --cc=tytso@mit.edu \
    --cc=yi.zhang@huawei.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®