KCSAN: data-race in __filemap_add_folio / filemap_write_and_wait_range (2)

Status: moderation: reported on 2026/11/12 12:30
Subsystems: ext4
Labels: prio:low race:benign
[Documentation on labels]
Reported-by: syzbot+79a93585914b2555125c@syzkaller.appspotmail.com
First crash: 1h06m, last: 1h06m
✨ AI-generated root cause summary:

A data race occurs on mapping->nrpages between __filemap_add_folio() and mapping_needs_writeback() (called from filemap_write_and_wait_range()). In __filemap_add_folio(), mapping->nrpages += nr; updates the counter under the XArray lock (mapping->i_pages.xa_lock) using an unmarked plain store. Concurrently, filemap_write_and_wait_range() calls mapping_needs_writeback() which performs an unsynchronized, lockless plain read (return mapping->nrpages;) without READ_ONCE() or data_race(). Because neither access uses atomic accessors or KCSAN annotations, KCSAN flags the concurrent read and write as a data race.

▶ ▼ ✨ Full AI root cause analysis
Based on kernel commit 79eb6679ef6a:

Root Cause Analysis

1. Functions, Structs, and Fields Involved

  • File: mm/filemap.c
  • Struct: struct address_space (include/linux/fs.h)
  • Field: mapping->nrpages (unsigned long, offset 80 bytes within struct address_space), serialized on writes by the XArray spinlock (mapping->i_pages.xa_lock).
  • Concurrent Functions:
    • Writer: __filemap_add_folio() (mm/filemap.c:918), reached via bdev_getblk() / ext4_sb_bread_unmovable() during ext4_fill_super() on mount().
    • Reader: mapping_needs_writeback() (mm/filemap.c:633), inlined into filemap_write_and_wait_range() (mm/filemap.c:682), reached via sync_blockdev() / bdev_release() on close().

2. Triggering Mechanism & Concurrency Breakdown

  1. Write Path (Task 4147, CPU 1):

    • While mounting a filesystem, task 4147 reads filesystem metadata blocks from the block device.
    • In __filemap_add_folio(), it inserts a newly allocated folio into mapping->i_pages.
    • The writer acquires the XArray lock via xas_lock_irq(&xas) and stores the folio into the XArray.
    • At mm/filemap.c:918, it increments the page counter:
      mapping->nrpages += nr;
      
      This update is an unmarked, plain C read-modify-write (+=) without WRITE_ONCE().
  2. Read Path (Task 2985, CPU 0):

    • Concurrently, task 2985 closes a file descriptor targeting the same block device, triggering bdev_release() $\to$ sync_blockdev() $\to$ filemap_write_and_wait().
    • filemap_write_and_wait_range() executes an opportunistic fast-path check:
      if (mapping_needs_writeback(mapping)) {
      
      which inlines mapping_needs_writeback():
      static bool mapping_needs_writeback(struct address_space *mapping)
      {
          return mapping->nrpages;
      }
      
    • This read is performed locklessly (without holding mapping->i_pages.xa_lock) and uses an unmarked, plain C read (mapping->nrpages) rather than READ_ONCE() or data_race().
  3. Data Race:

    • Under the Linux Kernel Memory Model (LKMM), concurrent unmarked plain accesses where at least one is a write constitute a data race.
    • KCSAN observed the simultaneous 8-byte write (0x0 -> 0x1) in __filemap_add_folio() and lockless load in mapping_needs_writeback(), triggering the splat.

3. Invariant / Lifecycle Evaluation & Fix

  • mapping_needs_writeback() is intended purely as a fast-path optimization to skip filemap_fdatawrite_range() and __filemap_fdatawait_range() when no pages are mapped.
  • Even if a concurrent caller reads 0 while a folio is being added to the mapping, the newly added folio has not yet been modified or marked dirty, meaning there is no dirty data or in-flight writeback to flush or wait upon. If it reads a non-zero value, writeback routines safely proceed to inspect the XArray tags (PAGECACHE_TAG_DIRTY / PAGECACHE_TAG_WRITEBACK) under RCU and lock protection.
  • To eliminate the data race under KCSAN and comply with LKMM:
    • The lockless fast-path reader should read the counter using data_race(READ_ONCE(mapping->nrpages)) (or READ_ONCE(mapping->nrpages) / data_race(...), similar to usage in mm/shmem.c).
    • Writes in mm/filemap.c (__filemap_add_folio, page_cache_delete, etc.) should annotate concurrent modifications with WRITE_ONCE() or data_race().
▶ ▼ ✨ AI Jobs (2)
ID Workflow Result Correct Bug Created Started Finished Revision
39eff813 assessment-security DenialOfService: ❌ Exploitable: ❌ FilesystemTrigger: ❌ FuzzingArtifact: ❌ MemoryCorruption: ❌ NetworkNeedsSetup: ❌ NetworkTrigger: ❌ PeripheralTrigger: ❌ RemoteTrigger: ❌ Unprivileged: ✅ UserNamespace: ✅ VMGuestTrigger: ❌ VMHostTrigger: ❌ ❓ KCSAN: data-race in __filemap_add_folio / filemap_write_and_wait_range (2) 2026/11/12 11:42 2026/11/12 11:42 2026/11/12 12:21 8d68b303
fedf6773 assessment-kcsan Benign: ✅ ❓ KCSAN: data-race in __filemap_add_folio / filemap_write_and_wait_range (2) 2026/11/12 11:42 2026/11/12 11:42 2026/11/12 12:43 8d68b303
▶ ▼ Similar bugs (1)
Kernel Title Rank 🛈 Repro Cause bisect Fix bisect Count Last Reported Patched Status
upstream KCSAN: data-race in __filemap_add_folio / filemap_write_and_wait_range prio:low mm 6 969 82d 1770d 0/29 auto-obsoleted due to no activity on 2026/10/10 05:48

Sample crash report:
==================================================================
BUG: KCSAN: data-race in __filemap_add_folio / filemap_write_and_wait_range

read-write to 0xffff8881004c3578 of 8 bytes by task 4147 on cpu 1:
 __filemap_add_folio+0x6c4/0x930 mm/filemap.c:918
 filemap_add_folio+0x1cd/0x380 mm/filemap.c:970
 __filemap_get_folio_mpol+0x309/0x830 mm/filemap.c:2057
 __filemap_get_folio include/linux/pagemap.h:758 [inline]
 grow_dev_folio fs/buffer.c:856 [inline]
 grow_buffers fs/buffer.c:922 [inline]
 __getblk_slow fs/buffer.c:940 [inline]
 bdev_getblk+0x127/0x370 fs/buffer.c:1350
 sb_getblk_gfp include/linux/buffer_head.h:448 [inline]
 __ext4_sb_bread_gfp fs/ext4/super.c:248 [inline]
 ext4_sb_bread_unmovable+0x65/0x180 fs/ext4/super.c:277
 ext4_load_super fs/ext4/super.c:5214 [inline]
 __ext4_fill_super fs/ext4/super.c:5420 [inline]
 ext4_fill_super+0x44b/0x37d0 fs/ext4/super.c:5899
 get_tree_bdev_flags+0x297/0x300 fs/super.c:1821
 get_tree_bdev+0x1f/0x30 fs/super.c:1844
 ext4_get_tree+0x1c/0x30 fs/ext4/super.c:5931
 vfs_get_tree+0x57/0x1d0 fs/super.c:1881
 fc_mount fs/namespace.c:1282 [inline]
 do_new_mount_fc fs/namespace.c:3910 [inline]
 do_new_mount+0x288/0x730 fs/namespace.c:3986
 path_mount+0x4ad/0xba0 fs/namespace.c:4337
 do_mount fs/namespace.c:4350 [inline]
 __do_sys_mount fs/namespace.c:4565 [inline]
 __se_sys_mount+0x28c/0x2e0 fs/namespace.c:4542
 __x64_sys_mount+0x67/0x80 fs/namespace.c:4542
 x64_sys_call+0xc3b/0x2550 arch/x86/include/generated/asm/syscalls_64.h:166
 do_syscall_x64 arch/x86/entry/syscall_64.c:61 [inline]
 do_syscall_64+0x116/0x380 arch/x86/entry/syscall_64.c:89
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

read to 0xffff8881004c3578 of 8 bytes by task 2985 on cpu 0:
 mapping_needs_writeback mm/filemap.c:633 [inline]
 filemap_write_and_wait_range+0x59/0x370 mm/filemap.c:682
 filemap_write_and_wait include/linux/pagemap.h:64 [inline]
 sync_blockdev block/bdev.c:275 [inline]
 bdev_release+0xd4/0x3d0 block/bdev.c:1171
 blkdev_release+0x15/0x20 block/fops.c:690
 __fput+0x286/0x610 fs/file_table.c:512
 fput_close_sync+0xad/0x190 fs/file_table.c:618
 filp_close_sync fs/open.c:1574 [inline]
 __do_sys_close fs/open.c:1597 [inline]
 __se_sys_close fs/open.c:1584 [inline]
 __x64_sys_close+0x55/0xf0 fs/open.c:1584
 x64_sys_call+0x812/0x2550 arch/x86/include/generated/asm/syscalls_64.h:4
 do_syscall_x64 arch/x86/entry/syscall_64.c:61 [inline]
 do_syscall_64+0x116/0x380 arch/x86/entry/syscall_64.c:89
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

value changed: 0x0000000000000000 -> 0x0000000000000001

Reported by Kernel Concurrency Sanitizer on:
CPU: 0 UID: 0 PID: 2985 Comm: udevd Not tainted syzkaller #0 PREEMPT(lazy) 
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 11/06/2026
==================================================================

Crashes (1):
Time Kernel Commit Syzkaller Config Log Report Syz repro C repro VM info Assets (help?) Manager Title
2026/11/12 11:42 upstream 79eb6679ef6a 8d68b303 .config console log report info [disk image] [vmlinux] [kernel image] ci2-upstream-kcsan-gce KCSAN: data-race in __filemap_add_folio / filemap_write_and_wait_range
* Struck through repros no longer work on HEAD.