In the Linux kernel, the following vulnerability has been resolved:
ntfs: skip extent mft records in writeback to prevent deadlock
This patch fixes the ABBA deadlock between extentlock and extent mreclock triggered by xfstests generic/113, that occurs since the commit 6994acf33bae ("ntfs: use base mft_no when looking up base inode for extent record").
Path A (inode writeback): VFS writeback -> ntfswriteinode() -> __ntfswriteinode() -> mutexlock(&ni->extentlock) -> mutexlock(&tni->mreclock)
Path B (MFT folio writeback): VFS writeback of $MFT dirty folios -> ntfsmftwritepages() -> ntfswritemftblock() -> ntfsmaywritemftrecord() -> holds one extent mreclock from a previous iteration -> tries to acquire another base inode extent_lock
By removing all extentlock and extent mreclock acquisition from the MFT folio writeback path, the ABBA lock ordering is eliminated:
Path A: _ntfswriteinode(): extentlock -> mreclock Path B (removed): ntfswritemftblock(): mreclock -> extentlock
Path B is always redundant for extent records because:
markmftrecorddirty(extni) does NOT dirty the MFT folio. It only sets NInoDirty(ext_ni) and marks the base VFS inode dirty via __markinodedirty(IDIRTYDATASYNC), which triggers Path A. Therefore, normal extent modifications never create a situation where the MFT folio is dirty and Path B is not scheduled.
The MFT folio only gets dirtied via ntfsmftmarkdirty() inside ntfsmftrecordalloc(). But all identified callers in attrib.c (ntfsattradd, ntfsattrrecordmoveaway, ntfsattrmakenonresident, ntfsattrrecordresize) follow through with markmftrecorddirty(), which triggers Path A to write the complete record.
ntfsevictbiginode() calls ntfscommit_inode() before freeing extent inodes, ensuring all dirty extents are flushed via Path A before the base inode leaves the icache.