ext4: lockdep: handle i_data_sem subclassing for special inodes

Fast commit can hold s_fc_lock while writing journal blocks. Mapping the
journal inode can take its i_data_sem. Normal inode update paths can take a
data inode i_data_sem and then s_fc_lock, which makes lockdep report a
circular dependency.

lockdep treats all i_data_sem instances as one lock class and cannot
distinguish the journal inode i_data_sem from a regular inode i_data_sem.
The journal inode is not tracked by fast commit and no FC waiters ever
depend on it, so this is not a real ABBA deadlock. Assign the journal inode
a dedicated i_data_sem lockdep subclass to avoid the false positive.

Inode cache objects can be recycled, so also reset i_data_sem to
I_DATA_SEM_NORMAL when allocating an ext4 inode. Otherwise a new inode may
inherit an old subclass (journal/quota/ea) and trigger lockdep warnings.

Signed-off-by: Li Chen <chenl311@chinatelecom.cn>
Link: https://patch.msgid.link/20260515091829.194810-3-me@linux.beauty
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
This commit is contained in:
Li Chen 2026-05-15 17:18:22 +08:00 committed by Theodore Ts'o
parent e9c6e0b8e0
commit 7f473f9713
2 changed files with 11 additions and 1 deletions

View File

@ -1015,12 +1015,14 @@ do { \
* than the first
* I_DATA_SEM_QUOTA - Used for quota inodes only
* I_DATA_SEM_EA - Used for ea_inodes only
* I_DATA_SEM_JOURNAL - Used for journal inode only
*/
enum {
I_DATA_SEM_NORMAL = 0,
I_DATA_SEM_OTHER,
I_DATA_SEM_QUOTA,
I_DATA_SEM_EA
I_DATA_SEM_EA,
I_DATA_SEM_JOURNAL
};
struct ext4_fc_inode_snap;

View File

@ -1431,6 +1431,9 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
ext4_fc_init_inode(&ei->vfs_inode);
spin_lock_init(&ei->i_fc_lock);
mmb_init(&ei->i_metadata_bhs, &ei->vfs_inode.i_data);
#ifdef CONFIG_LOCKDEP
lockdep_set_subclass(&ei->i_data_sem, I_DATA_SEM_NORMAL);
#endif
return &ei->vfs_inode;
}
@ -5910,6 +5913,11 @@ static struct inode *ext4_get_journal_inode(struct super_block *sb,
return ERR_PTR(-EFSCORRUPTED);
}
#ifdef CONFIG_LOCKDEP
lockdep_set_subclass(&EXT4_I(journal_inode)->i_data_sem,
I_DATA_SEM_JOURNAL);
#endif
ext4_debug("Journal inode found at %p: %lld bytes\n",
journal_inode, journal_inode->i_size);
return journal_inode;