[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAKa5YKiTodi=aDMqa8gb4o+4RAdis=-OYFv4HP9nQ3EHcCTzMA@mail.gmail.com>
Date: Thu, 26 Jun 2025 16:23:43 +0800
From: haoran zheng <zhenghaoran154@...il.com>
To: clm@...com, josef@...icpanda.com, dsterba@...e.com
Cc: linux-btrfs@...r.kernel.org, linux-kernel@...r.kernel.org,
baijiaju1990@...il.com, zzzccc427@...il.com
Subject: [BUG] Five data races in btrfs
[BUG] Five data races in btrfs
Hello maintainers,
I would like to report five data race bugs we discovered in the BTRFS
filesystem on Linux kernel v6.16-rc3. These issues were identified
using our data race detector.
We are currently analyzing the Btrfs codebase and have identified
several instances that may involve potential data races during
concurrent execution. While we have reviewed the relevant code
paths carefully, we are uncertain whether these issues could lead
to any practical impact or system instability.
Below is a summary of the findings:
---
1. Race between `__btrfs_set_fs_incompat()` and `btrfs_fs_incompat()`
`__btrfs_set_fs_incompat()` performs a write to the
`super_copy->incompat_flags` field under `fs_info->super_lock` while
`btrfs_need_stripe_tree_update()` calls `btrfs_fs_incompat()` without
acquiring `super_lock`, which may read a stale or partially updated
value of `incompat_flags`.
===========================DATARACE===========================
__btrfs_set_fs_incompat+0x12b/0x150 fs/btrfs/fs.c:150
btrfs_ioctl_default_subvol+0x2e5/0x380 fs/btrfs/ioctl.c:2930
btrfs_ioctl+0xd1f/0xe40 fs/btrfs/ioctl.c:5249
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:906 [inline]
__se_sys_ioctl+0x91/0xf0 fs/ioctl.c:892
do_syscall_x64 arch/x86/entry/common.c:52 [inline]
do_syscall_64+0xc9/0x1a0 arch/x86/entry/common.c:83
entry_SYSCALL_64_after_hwframe+0x77/0x7f
0x0
============OTHER_INFO============
get_unaligned_le64 include/linux/unaligned.h:28 [inline]
btrfs_super_incompat_flags fs/btrfs/accessors.h:890 [inline]
btrfs_need_stripe_tree_update fs/btrfs/raid-stripe-tree.h:42 [inline]
btrfs_map_block+0x426/0x1960 fs/btrfs/volumes.c:6674
btrfs_submit_chunk fs/btrfs/bio.c:694 [inline]
btrfs_submit_bbio+0x291/0xa70 fs/btrfs/bio.c:799
write_one_eb+0x8d8/0x960 fs/btrfs/extent_io.c:1828
submit_eb_page fs/btrfs/extent_io.c:1985 [inline]
btree_write_cache_pages+0x3b1/0x8e0 fs/btrfs/extent_io.c:2035
btree_writepages+0x6b/0x190 fs/btrfs/disk-io.c:520
do_writepages+0x102/0x370 mm/page-writeback.c:2687
filemap_fdatawrite_wbc mm/filemap.c:389 [inline]
__filemap_fdatawrite_range mm/filemap.c:422 [inline]
filemap_fdatawrite_range+0x9a/0xd0 mm/filemap.c:440
btrfs_write_marked_extents+0x130/0x230 fs/btrfs/transaction.c:1150
btrfs_sync_log+0xcfd/0x11f0 fs/btrfs/tree-log.c:3113
btrfs_sync_file+0x74b/0xaa0 fs/btrfs/file.c:1692
generic_write_sync include/linux/fs.h:2970 [inline]
btrfs_do_write_iter+0x4ba/0x5a0 fs/btrfs/file.c:1391
btrfs_file_write_iter+0x3d/0x60 fs/btrfs/file.c:1401
new_sync_write fs/read_write.c:586 [inline]
vfs_write+0x379/0x580 fs/read_write.c:679
ksys_write+0x93/0x120 fs/read_write.c:731
do_syscall_x64 arch/x86/entry/common.c:52 [inline]
do_syscall_64+0xc9/0x1a0 arch/x86/entry/common.c:83
entry_SYSCALL_64_after_hwframe+0x77/0x7f
=================================
---
2. Race between `btrfs_defrag_file()` and `inode_need_compress()`
In `btrfs_defrag_file()`, the field `inode->defrag_compress` is
assigned while holding the inode lock via `btrfs_inode_lock()`.
But in `inode_need_compress()`, the same field is read without
any apparent locking or memory barrier.
===========================DATARACE===========================
btrfs_defrag_file+0x127d/0x1570 fs/btrfs/defrag.c:1501
btrfs_ioctl_defrag+0x256/0x2f0 fs/btrfs/ioctl.c:2574
btrfs_ioctl+0xba4/0xe40
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:906 [inline]
__se_sys_ioctl+0x91/0xf0 fs/ioctl.c:892
do_syscall_x64 arch/x86/entry/common.c:52 [inline]
do_syscall_64+0xc9/0x1a0 arch/x86/entry/common.c:83
entry_SYSCALL_64_after_hwframe+0x77/0x7f
0x0
============OTHER_INFO============
inode_need_compress fs/btrfs/inode.c:788 [inline]
btrfs_run_delalloc_range+0x206/0x8a0 fs/btrfs/inode.c:2336
writepage_delalloc+0x52c/0x8b0 fs/btrfs/extent_io.c:1255
extent_writepage fs/btrfs/extent_io.c:1558 [inline]
extent_write_cache_pages fs/btrfs/extent_io.c:2248 [inline]
btrfs_writepages+0x930/0xe70 fs/btrfs/extent_io.c:2376
do_writepages+0x102/0x370 mm/page-writeback.c:2687
filemap_fdatawrite_wbc mm/filemap.c:389 [inline]
__filemap_fdatawrite_range mm/filemap.c:422 [inline]
filemap_fdatawrite_range+0x9a/0xd0 mm/filemap.c:440
btrfs_fdatawrite_range+0x6b/0xf0 fs/btrfs/file.c:3701
btrfs_direct_write+0x37d/0x6b0 fs/btrfs/direct-io.c:960
btrfs_do_write_iter+0x21f/0x5a0 fs/btrfs/file.c:1381
btrfs_file_write_iter+0x3d/0x60 fs/btrfs/file.c:1401
new_sync_write fs/read_write.c:586 [inline]
vfs_write+0x379/0x580 fs/read_write.c:679
ksys_write+0x93/0x120 fs/read_write.c:731
do_syscall_x64 arch/x86/entry/common.c:52 [inline]
do_syscall_64+0xc9/0x1a0 arch/x86/entry/common.c:83
entry_SYSCALL_64_after_hwframe+0x77/0x7f
=================================
---
3. Race between `join_transaction()` and `btrfs_get_fs_generation()`
In `join_transaction()`, `fs_info->generation` is assigned while
holding the lock `fs_info->trans_lock`. But reads of
`fs_info->generation` are done using READ_ONCE() in
`btrfs_get_fs_generation()`.
===========================DATARACE===========================
join_transaction+0x6ee/0x740 fs/btrfs/transaction.c:390
start_transaction+0x54e/0xea0 fs/btrfs/transaction.c:699
btrfs_join_transaction+0x42/0x60 fs/btrfs/transaction.c:823
btrfs_dirty_inode+0xa6/0x1c0 fs/btrfs/inode.c:6093
btrfs_update_time+0xa3/0xe0 fs/btrfs/inode.c:6127
inode_update_time fs/inode.c:2124 [inline]
touch_atime+0xb7/0x1d0 fs/inode.c:2197
file_accessed include/linux/fs.h:2601 [inline]
filemap_read+0x49d/0x520 mm/filemap.c:2763
btrfs_file_read_iter+0x71/0x190 fs/btrfs/file.c:3658
new_sync_read fs/read_write.c:484 [inline]
vfs_read+0x311/0x460 fs/read_write.c:565
ksys_read+0x93/0x120 fs/read_write.c:708
do_syscall_x64 arch/x86/entry/common.c:52 [inline]
do_syscall_64+0xc9/0x1a0 arch/x86/entry/common.c:83
entry_SYSCALL_64_after_hwframe+0x77/0x7f
0x0
============OTHER_INFO============
btrfs_get_fs_generation fs/btrfs/fs.h:915 [inline]
try_release_extent_mapping+0x13b/0x3a0 fs/btrfs/extent_io.c:2489
__btrfs_release_folio fs/btrfs/inode.c:7267 [inline]
btrfs_invalidate_folio+0x666/0x730 fs/btrfs/inode.c:7466
folio_invalidate mm/truncate.c:126 [inline]
truncate_cleanup_folio+0xf5/0x130 mm/truncate.c:146
truncate_inode_pages_range+0x126/0x4c0 mm/truncate.c:326
truncate_inode_pages mm/truncate.c:407 [inline]
truncate_pagecache mm/truncate.c:716 [inline]
truncate_setsize+0x71/0x90 mm/truncate.c:741
btrfs_setsize fs/btrfs/inode.c:5126 [inline]
btrfs_setattr+0x351/0xa30 fs/btrfs/inode.c:5165
notify_change+0x4d8/0x550 fs/attr.c:552
do_truncate+0x11b/0x160 fs/open.c:65
handle_truncate fs/namei.c:3451 [inline]
do_open fs/namei.c:3834 [inline]
path_openat+0xfad/0x1210 fs/namei.c:3989
do_filp_open+0xda/0x1d0 fs/namei.c:4016
do_sys_openat2+0x91/0x100 fs/open.c:1428
do_sys_open fs/open.c:1443 [inline]
__do_sys_open fs/open.c:1451 [inline]
__se_sys_open fs/open.c:1447 [inline]
__x64_sys_open+0xac/0xd0 fs/open.c:1447
do_syscall_x64 arch/x86/entry/common.c:52 [inline]
do_syscall_64+0xc9/0x1a0 arch/x86/entry/common.c:83
entry_SYSCALL_64_after_hwframe+0x77/0x7f
=================================
---
4. Race between `btrfs_super_bytes_used()` and `btrfs_update_block_group()`
In `btrfs_set_backup_bytes_used()`, super_copy is read and stored without
holding lock `info->delalloc_root_lock`. But in `btrfs_update_block_group()`
the `info->super_copy` is set concurrently.
===========================DATARACE===========================
get_unaligned_le64 include/linux/unaligned.h:28 [inline]
btrfs_super_bytes_used fs/btrfs/accessors.h:874 [inline]
backup_super_roots fs/btrfs/disk-io.c:1706 [inline]
write_all_supers+0xf9d/0x1dc0 fs/btrfs/disk-io.c:4101
btrfs_commit_transaction+0xf73/0x1c40 fs/btrfs/transaction.c:2528
transaction_kthread+0x1f8/0x330 fs/btrfs/disk-io.c:1602
kthread+0x2d5/0x300 kernel/kthread.c:464
ret_from_fork+0x4d/0x60 arch/x86/kernel/process.c:148
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:244
============OTHER_INFO============
btrfs_update_block_group+0xf0/0x7a0 fs/btrfs/block-group.c:3650
do_free_extent_accounting fs/btrfs/extent-tree.c:2975 [inline]
__btrfs_free_extent+0xde5/0x1d00 fs/btrfs/extent-tree.c:3338
btrfs_run_delayed_refs_for_head fs/btrfs/extent-tree.c:1976 [inline]
__btrfs_run_delayed_refs+0x5a3/0x1a50 fs/btrfs/extent-tree.c:2046
btrfs_run_delayed_refs+0xd1/0x2b0 fs/btrfs/extent-tree.c:2158
btrfs_commit_transaction+0x27a/0x1c40 fs/btrfs/transaction.c:2196
insert_balance_item fs/btrfs/volumes.c:3771 [inline]
btrfs_balance+0x11a4/0x1770 fs/btrfs/volumes.c:4647
btrfs_ioctl_balance+0x290/0x470 fs/btrfs/ioctl.c:3587
btrfs_ioctl+0xcaf/0xe40 fs/btrfs/ioctl.c:5305
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:906 [inline]
__se_sys_ioctl+0x91/0xf0 fs/ioctl.c:892
do_syscall_x64 arch/x86/entry/common.c:52 [inline]
do_syscall_64+0xc9/0x1a0 arch/x86/entry/common.c:83
entry_SYSCALL_64_after_hwframe+0x77
---
5. Race between `btrfs_defrag_file()` and `btrfs_defrag_file()`
In the function btrfs_defrag_file(), we also noticed a possible
race condition involving the writeback_index field of the
address_space structure associated with the inode. Specifically,
the code performs a read and conditional write without any
evident locking:
===========================DATARACE===========================
btrfs_defrag_file+0x2ca/0x1570 fs/btrfs/defrag.c:1426
btrfs_ioctl_defrag+0x256/0x2f0 fs/btrfs/ioctl.c:2574
btrfs_ioctl+0xd56/0xe40
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:906 [inline]
__se_sys_ioctl+0x91/0xf0 fs/ioctl.c:892
do_syscall_x64 arch/x86/entry/common.c:52 [inline]
do_syscall_64+0xc9/0x1a0 arch/x86/entry/common.c:83
entry_SYSCALL_64_after_hwframe+0x77/0x7f
0x0
============OTHER_INFO============
btrfs_defrag_file+0x2fa/0x1570 fs/btrfs/defrag.c:1427
btrfs_ioctl_defrag+0x256/0x2f0 fs/btrfs/ioctl.c:2574
btrfs_ioctl+0xd56/0xe40
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:906 [inline]
__se_sys_ioctl+0x91/0xf0 fs/ioctl.c:892
do_syscall_x64 arch/x86/entry/common.c:52 [inline]
do_syscall_64+0xc9/0x1a0 arch/x86/entry/common.c:83
entry_SYSCALL_64_after_hwframe+0x77/0x7f
=================================
Powered by blists - more mailing lists