[PATCH v2] mm/filemap: annotate lockless reads of mapping->nrpages

From: Nguyen Ngoc Thang

Date: Mon Oct 12 2026 - 08:23:11 EST


mapping->nrpages is updated under the i_pages lock but is read locklessly
as a cheap "anything cached?" hint, e.g. in invalidate_bdev() and
mapping_needs_writeback(). KCSAN reports the race:

BUG: KCSAN: data-race in __filemap_add_folio / invalidate_bdev

read-write to 0xffff8881004c4178 of 8 bytes by task 3600 on cpu 0:
__filemap_add_folio+0x6b7/0x910 mm/filemap.c:919
filemap_add_folio+0x1cd/0x380
page_cache_ra_unbounded+0x1a4/0x3a0
...
blkdev_read_iter+0x21e/0x2d0
read to 0xffff8881004c4178 of 8 bytes by task 3601 on cpu 1:
invalidate_bdev+0x25/0x70 block/bdev.c:98
ext4_fill_super+0x2ccb/0x37b0

The same counter also races with filemap_write_and_wait_range() through
mapping_needs_writeback().

The race is benign: a stale value only makes the caller do or skip a
harmless invalidate/flush pass. Mark the two lockless readers with
data_race().

Reported-by: syzbot+e0624b5bf72b99131402@xxxxxxxxxxxxxxxxxxxxxxxxx
Closes: https://syzkaller.appspot.com/bug?extid=e0624b5bf72b99131402
Signed-off-by: Nguyen Ngoc Thang <ngocthang2710.1999@xxxxxxxxx>
---
v2: Use data_race() on the two readers instead of READ_ONCE()/WRITE_ONCE()
pairs, as suggested by Jan Kara. v1: https://lore.kernel.org/all/20261011112940.455497-1-ngocthang2710.1999@xxxxxxxxx/

block/bdev.c | 3 ++-
mm/filemap.c | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/block/bdev.c b/block/bdev.c
index cd8323083740..233750f87e6d 100644
--- a/block/bdev.c
+++ b/block/bdev.c
@@ -95,7 +95,8 @@ void invalidate_bdev(struct block_device *bdev)
{
struct address_space *mapping = bdev->bd_mapping;

- if (mapping->nrpages) {
+ /* Lockless hint; a stale value only costs or skips a harmless pass */
+ if (data_race(mapping->nrpages)) {
invalidate_bh_lrus();
lru_add_drain_all(); /* make sure all lru add caches are flushed */
invalidate_mapping_pages(mapping, 0, -1);
diff --git a/mm/filemap.c b/mm/filemap.c
index 00fd89cf6f55..4c9d98efb7fb 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -631,7 +631,8 @@ EXPORT_SYMBOL(filemap_fdatawait_keep_errors);
/* Returns true if writeback might be needed or already in progress. */
static bool mapping_needs_writeback(struct address_space *mapping)
{
- return mapping->nrpages;
+ /* Lockless hint; a stale value is harmless */
+ return data_race(mapping->nrpages);
}

bool filemap_range_has_writeback(struct address_space *mapping,
--
2.43.0