]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ntfs: avoid self-deadlock during inode eviction
authorHyunchul Lee <hyc.lee@gmail.com>
Thu, 2 Jul 2026 05:28:16 +0000 (14:28 +0900)
committerNamjae Jeon <linkinjeon@kernel.org>
Mon, 6 Jul 2026 11:26:05 +0000 (20:26 +0900)
An attribute-list update performed while allocating clusters can drop the
last reference to the temporary attribute inode. Evicting that inode
drops its reference to the base inode and can invoke ntfs_drop_big_inode()
for the base inode from within the base inode's own writeback path.

If the base inode is unlinked, ntfs_drop_big_inode() calls
truncate_setsize(), which waits for the inode's folio writeback to
complete. The same writeback worker is responsible for completing that
writeback, so it waits for itself indefinitely.

Prevent this self-deadlock by grabbing a reference to the base inode at the
beginning of ntfs_writepages() and releasing it at the end of the function.
This defers eviction until all bios have been submitted, allowing the wait
for folio writeback to complete safely.

Fixes: b041ca562526 ("ntfs: update iomap and address space operations")
Cc: stable@vger.kernel.org
Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
fs/ntfs/aops.c

index 1fbf832ad1654093d032da409d54b8ecf46a136b..88e5b2def66caf4a6f19daa3930503f02886d686 100644 (file)
@@ -251,6 +251,8 @@ static int ntfs_writepages(struct address_space *mapping,
                .wbc            = wbc,
                .ops            = &ntfs_writeback_ops,
        };
+       bool need_iput = false;
+       int ret;
 
        if (NVolShutdown(ni->vol))
                return -EIO;
@@ -267,7 +269,20 @@ static int ntfs_writepages(struct address_space *mapping,
                return -EOPNOTSUPP;
        }
 
-       return iomap_writepages(&wpc);
+       /*
+        * Prevent eviction in writeback to avoid deadlock in
+        * ntfs_drop_big_inode().
+        */
+       if ((ni->type == AT_DATA || ni->type == AT_INDEX_ALLOCATION) &&
+           igrab(inode))
+               need_iput = true;
+
+       ret = iomap_writepages(&wpc);
+
+       if (need_iput)
+               iput(inode);
+
+       return ret;
 }
 
 static int ntfs_swap_activate(struct swap_info_struct *sis,