Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ocfs2: avoid potential ABBA deadlock by reordering tl_inode lock

In ocfs2_move_extent(), tl_inode is currently locked after the global
bitmap inode. However, in ocfs2_flush_truncate_log(), the lock order is
reversed: tl_inode is locked first, followed by the global bitmap inode.

This creates a classic ABBA deadlock scenario if two threads attempt these
operations concurrently and acquire the locks in different orders.

To prevent this, move the tl_inode locking earlier in ocfs2_move_extent(),
so that it always precedes the global bitmap inode lock.

No functional changes beyond lock ordering.

Link: https://lkml.kernel.org/r/20250708020640.387741-1-ipravdin.official@gmail.com
Reported-by: syzbot+6bf948e47f9bac7aacfa@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/all/67d5645c.050a0220.1dc86f.0004.GAE@google.com/
Signed-off-by: Ivan Pravdin <ipravdin.official@gmail.com>
Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Junxiao Bi <junxiao.bi@oracle.com>
Cc: Changwei Ge <gechangwei@live.cn>
Cc: Jun Piao <piaojun@huawei.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Ivan Pravdin and committed by
Andrew Morton
08eabe4b 97103dce

+9 -10
+9 -10
fs/ocfs2/move_extents.c
··· 617 617 */ 618 618 credits += OCFS2_INODE_UPDATE_CREDITS + 1; 619 619 620 + inode_lock(tl_inode); 621 + 620 622 /* 621 623 * ocfs2_move_extent() didn't reserve any clusters in lock_allocators() 622 624 * logic, while we still need to lock the global_bitmap. ··· 628 626 if (!gb_inode) { 629 627 mlog(ML_ERROR, "unable to get global_bitmap inode\n"); 630 628 ret = -EIO; 631 - goto out; 629 + goto out_unlock_tl_inode; 632 630 } 633 631 634 632 inode_lock(gb_inode); ··· 636 634 ret = ocfs2_inode_lock(gb_inode, &gb_bh, 1); 637 635 if (ret) { 638 636 mlog_errno(ret); 639 - goto out_unlock_gb_mutex; 637 + goto out_unlock_gb_inode; 640 638 } 641 - 642 - inode_lock(tl_inode); 643 639 644 640 handle = ocfs2_start_trans(osb, credits); 645 641 if (IS_ERR(handle)) { 646 642 ret = PTR_ERR(handle); 647 643 mlog_errno(ret); 648 - goto out_unlock_tl_inode; 644 + goto out_unlock; 649 645 } 650 646 651 647 new_phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, *new_phys_cpos); ··· 703 703 out_commit: 704 704 ocfs2_commit_trans(osb, handle); 705 705 brelse(gd_bh); 706 - 707 - out_unlock_tl_inode: 708 - inode_unlock(tl_inode); 709 - 706 + out_unlock: 710 707 ocfs2_inode_unlock(gb_inode, 1); 711 - out_unlock_gb_mutex: 708 + out_unlock_gb_inode: 712 709 inode_unlock(gb_inode); 713 710 brelse(gb_bh); 714 711 iput(gb_inode); 712 + out_unlock_tl_inode: 713 + inode_unlock(tl_inode); 715 714 716 715 out: 717 716 if (context->meta_ac) {