linux/fs
Chao Yu ca8b201f28 f2fs: fix to avoid potential deadlock
As Jiaming Zhang and syzbot reported, there is potential deadlock in
f2fs as below:

Chain exists of:
  &sbi->cp_rwsem --> fs_reclaim --> sb_internal#2

 Possible unsafe locking scenario:

       CPU0                    CPU1
       ----                    ----
  rlock(sb_internal#2);
                               lock(fs_reclaim);
                               lock(sb_internal#2);
  rlock(&sbi->cp_rwsem);

 *** DEADLOCK ***

3 locks held by kswapd0/73:
 #0: ffffffff8e247a40 (fs_reclaim){+.+.}-{0:0}, at: balance_pgdat mm/vmscan.c:7015 [inline]
 #0: ffffffff8e247a40 (fs_reclaim){+.+.}-{0:0}, at: kswapd+0x951/0x2800 mm/vmscan.c:7389
 #1: ffff8880118400e0 (&type->s_umount_key#50){.+.+}-{4:4}, at: super_trylock_shared fs/super.c:562 [inline]
 #1: ffff8880118400e0 (&type->s_umount_key#50){.+.+}-{4:4}, at: super_cache_scan+0x91/0x4b0 fs/super.c:197
 #2: ffff888011840610 (sb_internal#2){.+.+}-{0:0}, at: f2fs_evict_inode+0x8d9/0x1b60 fs/f2fs/inode.c:890

stack backtrace:
CPU: 0 UID: 0 PID: 73 Comm: kswapd0 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014
Call Trace:
 <TASK>
 dump_stack_lvl+0x189/0x250 lib/dump_stack.c:120
 print_circular_bug+0x2ee/0x310 kernel/locking/lockdep.c:2043
 check_noncircular+0x134/0x160 kernel/locking/lockdep.c:2175
 check_prev_add kernel/locking/lockdep.c:3165 [inline]
 check_prevs_add kernel/locking/lockdep.c:3284 [inline]
 validate_chain+0xb9b/0x2140 kernel/locking/lockdep.c:3908
 __lock_acquire+0xab9/0xd20 kernel/locking/lockdep.c:5237
 lock_acquire+0x120/0x360 kernel/locking/lockdep.c:5868
 down_read+0x46/0x2e0 kernel/locking/rwsem.c:1537
 f2fs_down_read fs/f2fs/f2fs.h:2278 [inline]
 f2fs_lock_op fs/f2fs/f2fs.h:2357 [inline]
 f2fs_do_truncate_blocks+0x21c/0x10c0 fs/f2fs/file.c:791
 f2fs_truncate_blocks+0x10a/0x300 fs/f2fs/file.c:867
 f2fs_truncate+0x489/0x7c0 fs/f2fs/file.c:925
 f2fs_evict_inode+0x9f2/0x1b60 fs/f2fs/inode.c:897
 evict+0x504/0x9c0 fs/inode.c:810
 f2fs_evict_inode+0x1dc/0x1b60 fs/f2fs/inode.c:853
 evict+0x504/0x9c0 fs/inode.c:810
 dispose_list fs/inode.c:852 [inline]
 prune_icache_sb+0x21b/0x2c0 fs/inode.c:1000
 super_cache_scan+0x39b/0x4b0 fs/super.c:224
 do_shrink_slab+0x6ef/0x1110 mm/shrinker.c:437
 shrink_slab_memcg mm/shrinker.c:550 [inline]
 shrink_slab+0x7ef/0x10d0 mm/shrinker.c:628
 shrink_one+0x28a/0x7c0 mm/vmscan.c:4955
 shrink_many mm/vmscan.c:5016 [inline]
 lru_gen_shrink_node mm/vmscan.c:5094 [inline]
 shrink_node+0x315d/0x3780 mm/vmscan.c:6081
 kswapd_shrink_node mm/vmscan.c:6941 [inline]
 balance_pgdat mm/vmscan.c:7124 [inline]
 kswapd+0x147c/0x2800 mm/vmscan.c:7389
 kthread+0x70e/0x8a0 kernel/kthread.c:463
 ret_from_fork+0x4bc/0x870 arch/x86/kernel/process.c:158
 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
 </TASK>

The root cause is deadlock among four locks as below:

kswapd
- fs_reclaim				--- Lock A
 - shrink_one
  - evict
   - f2fs_evict_inode
    - sb_start_intwrite			--- Lock B

- iput
 - evict
  - f2fs_evict_inode
   - sb_start_intwrite			--- Lock B
   - f2fs_truncate
    - f2fs_truncate_blocks
     - f2fs_do_truncate_blocks
      - f2fs_lock_op			--- Lock C

ioctl
- f2fs_ioc_commit_atomic_write
 - f2fs_lock_op				--- Lock C
  - __f2fs_commit_atomic_write
   - __replace_atomic_write_block
    - f2fs_get_dnode_of_data
     - __get_node_folio
      - f2fs_check_nid_range
       - f2fs_handle_error
        - f2fs_record_errors
         - f2fs_down_write		--- Lock D

open
- do_open
 - do_truncate
  - security_inode_need_killpriv
   - f2fs_getxattr
    - lookup_all_xattrs
     - f2fs_handle_error
      - f2fs_record_errors
       - f2fs_down_write		--- Lock D
        - f2fs_commit_super
         - read_mapping_folio
          - filemap_alloc_folio_noprof
           - prepare_alloc_pages
            - fs_reclaim_acquire	--- Lock A

In order to avoid such deadlock, we need to avoid grabbing sb_lock in
f2fs_handle_error(), so, let's use asynchronous method instead:
- remove f2fs_handle_error() implementation
- rename f2fs_handle_error_async() to f2fs_handle_error()
- spread f2fs_handle_error()

Fixes: 95fa90c9e5 ("f2fs: support recording errors into superblock")
Cc: stable@kernel.org
Reported-by: syzbot+14b90e1156b9f6fc1266@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/linux-f2fs-devel/68eae49b.050a0220.ac43.0001.GAE@google.com
Reported-by: Jiaming Zhang <r772577952@gmail.com>
Closes: https://lore.kernel.org/lkml/CANypQFa-Gy9sD-N35o3PC+FystOWkNuN8pv6S75HLT0ga-Tzgw@mail.gmail.com
Signed-off-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2025-12-04 01:59:59 +00:00
..
9p Revert "fs/9p: Refresh metadata in d_revalidate for uncached mode too" 2025-10-22 14:25:27 +09:00
adfs vfs-6.17-rc1.mmap_prepare 2025-07-28 13:43:25 -07:00
affs vfs-6.17-rc1.mmap_prepare 2025-07-28 13:43:25 -07:00
afs Simplifying ->d_name audits, easy part. 2025-10-03 11:14:02 -07:00
autofs new helper: set_default_d_op() 2025-06-10 22:21:16 -04:00
befs
bfs vfs-6.17-rc1.mmap_prepare 2025-07-28 13:43:25 -07:00
btrfs for-6.18-rc2-tag 2025-10-23 06:44:43 -10:00
cachefiles VFS: unify old_mnt_idmap and new_mnt_idmap in renamedata 2025-09-23 12:37:35 +02:00
ceph Some messenger improvements from Eric and Max, a patch to address the 2025-10-10 11:30:19 -07:00
coda vfs-6.17-rc1.mmap_prepare 2025-07-28 13:43:25 -07:00
configfs file->f_path constification 2025-10-03 16:32:36 -07:00
cramfs Patch series in this pull request: 2025-10-02 18:44:54 -07:00
crypto fscrypt updates for 6.18 2025-09-29 15:33:50 -07:00
debugfs vfs-6.18-rc1.async 2025-09-29 11:55:15 -07:00
devpts devpts, sunrpc, hostfs: don't bother with ->d_op 2025-06-11 13:40:04 -04:00
dlm dlm for 6.18 2025-09-29 15:24:58 -07:00
ecryptfs mount-related stuff for this cycle 2025-10-03 10:19:44 -07:00
efivarfs vfs-6.18-rc1.misc 2025-09-29 09:03:07 -07:00
efs
erofs erofs: consolidate z_erofs_extent_lookback() 2025-10-22 07:54:31 +08:00
exfat exfat: fix out-of-bounds in exfat_nls_to_ucs2() 2025-10-15 17:53:20 +09:00
exportfs exportfs: use lookup_one_unlocked() 2025-06-11 13:44:15 +02:00
ext2 \n 2025-07-28 16:16:09 -07:00
ext4 Ext4 bug fixes for 6.18-rc2, including 2025-10-15 07:51:57 -07:00
f2fs f2fs: fix to avoid potential deadlock 2025-12-04 01:59:59 +00:00
fat vfat: remove unused variable 2025-09-13 17:32:47 -07:00
freevxfs
fuse Revert "fs: make vfs_fileattr_[get|set] return -EOPNOTSUPP" 2025-10-10 13:44:03 +02:00
gfs2 finish_no_open calling conventions change 2025-10-03 10:59:31 -07:00
hfs hfs/hfsplus: rework debug output subsystem 2025-09-24 16:30:34 -07:00
hfsplus hfs/hfsplus: rework debug output subsystem 2025-09-24 16:30:34 -07:00
hostfs fs: rename generic_delete_inode() and generic_drop_inode() 2025-09-15 16:09:42 +02:00
hpfs - Avoid -Wflex-array-member-not-at-end warnings 2025-10-10 14:06:02 -07:00
hugetlbfs hugetlbfs: move lock assertions after early returns in huge_pmd_unshare() 2025-10-21 15:46:17 -07:00
iomap iomap: open code bio_iov_iter_get_bdev_pages 2025-10-07 08:05:44 -06:00
isofs Current exclusion rules for ->d_flags stores are rather unpleasant. 2025-07-28 09:17:57 -07:00
jbd2 jbd2: ensure that all ongoing I/O complete before freeing blocks 2025-10-10 13:10:06 -04:00
jffs2 mm: introduce memdesc_flags_t 2025-09-13 16:55:07 -07:00
jfs A few fixes and cleanups for JFS. 2025-10-03 13:54:23 -07:00
kernfs vfs-6.18-rc1.misc 2025-09-29 09:03:07 -07:00
lockd SUNRPC: Move the svc_rpcb_cleanup() call sites 2025-09-23 13:28:19 -04:00
minix minixfs: Verify inode mode when loading from disk 2025-08-19 13:30:46 +02:00
netfs vfs-6.18-rc1.workqueue 2025-09-29 10:27:17 -07:00
nfs NFS4: Fix state renewals missing after boot 2025-10-13 14:33:00 -04:00
nfs_common NFS/localio: nfs_uuid_put() fix the wake up after unlinking the file 2025-08-05 16:45:40 -07:00
nfsd nfsd-6.18 fixes: 2025-10-14 09:28:12 -07:00
nilfs2 Merge branch 'mm-hotfixes-stable' into mm-stable in order to pick up 2025-09-21 14:19:36 -07:00
nls
notify fs/notify: call exportfs_encode_fid with s_umount 2025-10-06 16:31:52 +02:00
ntfs3 ntfs3: stop using write_cache_pages 2025-09-13 16:55:13 -07:00
ocfs2 ocfs2: clear extent cache after moving/defragmenting extents 2025-10-15 13:24:33 -07:00
omfs vfs-6.17-rc1.mmap_prepare 2025-07-28 13:43:25 -07:00
openpromfs
orangefs orangefs: Two cleanups and a bug fix. 2025-10-03 13:59:56 -07:00
overlayfs ovl: remove redundant IOCB_DIO_CALLER_COMP clearing 2025-10-10 14:02:47 +02:00
proc Patch series in this pull request: 2025-10-02 18:44:54 -07:00
pstore pstore update for v6.18-rc1 2025-09-29 18:08:34 -07:00
qnx4
qnx6
quota fs: replace use of system_unbound_wq with system_dfl_wq 2025-09-19 16:15:07 +02:00
ramfs fs: rename generic_delete_inode() and generic_drop_inode() 2025-09-15 16:09:42 +02:00
resctrl fs/resctrl: Fix counter auto-assignment on mkdir with mbm_event enabled 2025-09-17 11:31:12 +02:00
romfs fs: replace mmap hook with .mmap_prepare for simple mappings 2025-06-19 13:56:59 +02:00
smb smb client fixes and some clealup 2025-10-18 07:11:32 -10:00
squashfs Patch series in this pull request: 2025-10-02 18:44:54 -07:00
sysfs sysfs: remove bin_attribute::read_new/write_new() 2025-08-19 13:12:12 +02:00
tests
tracefs Massage rpc_pipefs to use saner primitives and clean up the 2025-07-28 09:56:09 -07:00
ubifs Summary of significant series in this pull request: 2025-10-02 18:18:33 -07:00
udf fs: udf: fix OOB read in lengthAllocDescs handling 2025-09-22 15:33:56 +02:00
ufs vfs-6.17-rc1.mmap_prepare 2025-07-28 13:43:25 -07:00
unicode
vboxsf simplify vboxsf_dir_atomic_open() 2025-09-16 23:59:38 -04:00
verity Optimize fsverity with 2-way interleaved hashing 2025-09-29 15:55:20 -07:00
xfs xfs: new code for 6.18 2025-09-29 14:35:44 -07:00
zonefs zonefs: correct some spelling mistakes 2025-08-12 11:59:27 +09:00
aio.c Summary of significant series in this pull request: 2025-10-02 18:18:33 -07:00
anon_inodes.c module: Rename EXPORT_SYMBOL_GPL_FOR_MODULES to EXPORT_SYMBOL_FOR_MODULES 2025-08-11 16:16:36 +02:00
attr.c vfs: add ATTR_CTIME_SET flag 2025-09-21 19:24:50 -04:00
backing-file.c vfs-6.17-rc1.mmap_prepare 2025-07-28 13:43:25 -07:00
bad_inode.c
binfmt_elf_fdpic.c execve updates for v6.17 2025-07-28 17:11:40 -07:00
binfmt_elf.c binfmt_elf: preserve original ELF e_flags for core dumps 2025-09-03 20:49:32 -07:00
binfmt_flat.c
binfmt_misc.c binfmt_misc: switch to locked_recursive_removal() 2025-07-02 22:36:51 -04:00
binfmt_script.c
bpf_fs_kfuncs.c bpf...d_path(): constify path argument 2025-09-15 21:17:08 -04:00
buffer.c fs/buffer: fix use-after-free when call bh_read() helper 2025-08-19 13:51:28 +02:00
char_dev.c
compat_binfmt_elf.c
coredump.c coredump: fix core_pattern input validation 2025-10-07 13:12:46 +02:00
d_path.c fold fs_struct->{lock,seq} into a seqlock 2025-07-08 10:25:19 +02:00
dax.c dax: skip read lock assertion for read-only filesystems 2025-10-07 12:48:33 +02:00
dcache.c vfs: Don't leak disconnected dentries on umount 2025-10-07 13:09:08 +02:00
direct-io.c Summary of significant series in this pull request: 2025-07-31 14:57:54 -07:00
drop_caches.c
eventfd.c
eventpoll.c eventpoll: Replace rwlock with spinlock 2025-09-05 15:51:24 +02:00
exec.c coredump: fix core_pattern input validation 2025-10-07 13:12:46 +02:00
fcntl.c fcntl: trim arguments 2025-09-26 10:21:23 +02:00
fhandle.c namespace-6.18-rc1 2025-09-29 11:20:29 -07:00
file_attr.c fs: return EOPNOTSUPP from file_setattr/file_getattr syscalls 2025-10-10 13:46:00 +02:00
file_table.c fs: update comment in init_file() 2025-10-07 12:48:33 +02:00
file.c fs: always return zero on success from replace_fd() 2025-08-11 14:52:25 +02:00
filesystems.c
fs_context.c change the calling conventions for vfs_parse_fs_string() 2025-09-04 15:20:51 -04:00
fs_parser.c
fs_pin.c
fs_struct.c fold fs_struct->{lock,seq} into a seqlock 2025-07-08 10:25:19 +02:00
fs_types.c
fs-writeback.c vfs-6.18-rc1.writeback 2025-09-29 11:34:40 -07:00
fsopen.c fscontext: do not consume log entries when returning -EMSGSIZE 2025-08-11 14:52:41 +02:00
init.c VFS: rename kern_path_locked() and related functions. 2025-09-23 12:37:36 +02:00
inode.c vfs-6.18-rc1.inode 2025-09-29 09:42:30 -07:00
internal.h file->f_path constification 2025-10-03 16:32:36 -07:00
ioctl.c fs: remove vfs_ioctl export 2025-09-01 13:08:01 +02:00
Kconfig Summary of significant series in this pull request: 2025-10-02 18:18:33 -07:00
Kconfig.binfmt binfmt_elf: preserve original ELF e_flags for core dumps 2025-09-03 20:49:32 -07:00
kernel_read_file.c
libfs.c vfs-6.17-rc1.pidfs 2025-07-28 14:10:15 -07:00
locks.c locks: Remove the last reference to EXPORT_OP_ASYNC_LOCK. 2025-08-11 14:52:24 +02:00
Makefile Remove bcachefs core code 2025-09-29 13:43:52 -07:00
mbcache.c
mnt_idmapping.c
mount.h mount-related stuff for this cycle 2025-10-03 10:19:44 -07:00
mpage.c mpage: convert do_mpage_readpage() to return void type 2025-09-21 14:22:16 -07:00
namei.c file->f_path constification 2025-10-03 16:32:36 -07:00
namespace.c vfs_parse_fs_string() stuff 2025-10-03 10:51:44 -07:00
nsfs.c nsfs: handle inode number mismatches gracefully in file handles 2025-10-07 12:48:33 +02:00
open.c file->f_path constification 2025-10-03 16:32:36 -07:00
pidfs.c file->f_path constification 2025-10-03 16:32:36 -07:00
pipe.c Add RWF_NOSIGNAL flag for pwritev2 2025-08-29 15:08:07 +02:00
pnode.c umount_tree(): take all victims out of propagation graph at once 2025-09-15 21:26:44 -04:00
pnode.h umount_tree(): take all victims out of propagation graph at once 2025-09-15 21:26:44 -04:00
posix_acl.c
proc_namespace.c ->mnt_devname is never NULL 2025-05-23 14:20:44 +02:00
read_write.c copy_file_range: limit size if in compat mode 2025-08-15 16:11:47 +02:00
readdir.c readdir: supply dir_context.count as readdir buffer size hint 2025-05-29 12:31:23 +02:00
remap_range.c
select.c fs: annotate suspected data race between poll_schedule_timeout() and pollwake() 2025-06-23 12:36:51 +02:00
seq_file.c
signalfd.c
splice.c netfs: Fix unbuffered write error handling 2025-08-15 15:56:49 +02:00
stack.c docs/vfs: update references to i_mutex to i_rwsem 2025-06-23 12:17:33 +02:00
stat.c constify path argument of vfs_statx_path() 2025-09-15 21:17:07 -04:00
statfs.c
super.c mount-related stuff for this cycle 2025-10-03 10:19:44 -07:00
sync.c
sysctls.c
timerfd.c
userfaultfd.c mm/mremap: use an explicit uffd failure path for mremap 2025-07-24 19:12:29 -07:00
utimes.c
xattr.c vfs-6.17-rc1.misc 2025-07-28 11:22:56 -07:00