From: Baolin Wang <baolin.wang@linux.alibaba.com>
To: Pedro Falcato <pfalcato@suse.de>, Ayush Ranjan <ayushr@modal.com>
Cc: Hugh Dickins <hughd@google.com>,
Matthew Wilcox <willy@infradead.org>,
Andrew Morton <akpm@linux-foundation.org>,
Jan Kara <jack@suse.cz>, David Hildenbrand <david@kernel.org>,
Gregory Price <gourry@gourry.net>,
linux-mm@kvack.org, linux-fsdevel@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: Re: [BUG] shmem: FALLOC_FL_PUNCH_HOLE vs fault-around race corrupts page cache / rss counters
Date: Thu, 24 Sep 2026 17:30:12 +0800 [thread overview]
Message-ID: <61f8a9af-7cdc-4979-bcc0-bcc932f7301f@linux.alibaba.com> (raw)
In-Reply-To: <arTdLsBENhrpOyk-@pedro-suse.tail5790ac.ts.net>
On 9/24/26 4:34 PM, Pedro Falcato wrote:
> (please use the email I actually use for work, thanks; not sure how
> you got to that one)
>
> Hi,
>
> On Thu, Sep 24, 2026 at 06:16:21AM +0000, Ayush Ranjan wrote:
>> Hi,
>>
>> We are seeing shmem/tmpfs page cache corruption on production hosts
>> running a workload that punches holes in a memfd (hole-punch based
>> memory reclaim) while other threads and forked children fault the
>> same MAP_SHARED mapping. The kernel taints but does not oops:
>>
>> BUG: Bad page cache in process ... pfn:...
>> page dumped because: still mapped when deleted
>> ...
>> dentry name(?): "memfd:..."
>>
>> and, more frequently, a paired rss-counter imbalance when the mm is
>> torn down, always exactly one PMD-order folio (512 pages):
>>
>> BUG: Bad rss-counter state mm:... type:MM_FILEPAGES val:-512
>> BUG: Bad rss-counter state mm:... type:MM_SHMEMPAGES val:512
>>
>> Seen on 6.12 and 6.18, x86_64, bare metal and VM, with
>> /sys/kernel/mm/transparent_hugepage/shmem_enabled = always.
>>
>> This looks like the same corruption Gregory reported in March, which
>> as far as I can tell stalled without a fix; that report needed ~100
>> ballooning VMs to reproduce:
>
> Well, I thought (from the lack of replies) that it was probably a bug on
> their side. Perhaps that's not true :/
>
>>
>> https://patchew.org/linux/20260326162611.693539-1-gourry@gourry.net/
>>
>> The reproducer at the end of this mail trips it with a single memfd,
>> no VMs or ballooning, within a few minutes on a large machine, so
>> hopefully it makes the race easier to confirm (and to test a fix
>> against).
>>
>> Here is my best understanding of the race -- corrections welcome:
>>
>> shmem guards faults against an in-progress hole punch with
>> inode->i_private: shmem_fault() -> shmem_falloc_wait() waits while
>> shmem_fallocate(PUNCH_HOLE) holds i_private. But shmem's .map_pages
>> is the generic filemap_map_pages() (shmem_vm_ops /
>> shmem_anon_vm_ops), which does not consult i_private and does not
>> take invalidate_lock, and shmem does not use invalidate_lock to
>> serialize faults against truncation the way regular filesystems do --
>> the i_private + waitq scheme stands in for it, but only shmem_fault()
>> participates in that scheme.
>>
>> So while shmem_fallocate(PUNCH_HOLE) is between
>> unmap_mapping_range() and shmem_truncate_range(), a concurrent
>> fault-around can (re-)install PTEs for folios that are about to be
>> truncated:
>>
>> - filemap_map_pages() samples mm_counter_file(folio) once per batch
>> and applies it with add_mm_counter() after mapping; if the
>> folio's swapbacked state changes while it is concurrently torn
>
> But that cannot happen? We hold the folio lock in filemap_map_pages().
> The folio (naturally) cannot be torn down while we have the folio lock.
>
>> down, the map-time counter (MM_FILEPAGES) and the zap-time
>> counter (MM_SHMEMPAGES) disagree by exactly one folio -- the
>> +/-512 imbalance above.
>>
>> - a folio re-mapped in this window (by fault-around directly, or
>> via a child VMA whose PTEs copy_page_range() installs after
>> unmap_mapping_range() has already walked the i_mmap tree -- the
>> dup_mmap() variant discussed in the earlier thread) can be
>> deleted from the page cache while still mapped -> "still mapped
>> when deleted".
>
> No, I don't think this paragraph is true. Page cache truncation (via
> truncate, or fallocate PUNCH_HOLE) takes the folio lock for each folio
> that is about to be truncated out. Mapping folios takes the folio lock
> as well, except in the fork() case where a myriad of weird interval tree
> + PTE lock interactions make it safe (AIUI).
Agree.
However, I did previously fix a race between filemap_map_pages() and
truncation that caused incorrect folio mappings, and I believe this race
also exists in shmem. Ayush, could you check whether that fix is present
in your kernel?
f58df566524e ("mm: filemap: fix nr_pages calculation overflow in
filemap_map_pages()")
>> Reproducer
>> ----------
>>
>> The race is on PMD-order folios, so khugepaged needs to scan
>> aggressively (with the default 10s scan interval the punched ranges
>> are not re-collapsed fast enough to reproduce quickly):
>>
>> echo always > /sys/kernel/mm/transparent_hugepage/shmem_enabled
>> cd /sys/kernel/mm/transparent_hugepage/khugepaged
>> echo 1 > scan_sleep_millisecs
>> echo 4096 > pages_to_scan
>> echo 511 > max_ptes_none
>>
>> cc -O2 -pthread -o repro repro_shmem_punch_race.c
>> for i in $(seq $(( $(nproc) / 3 ))); do ./repro 60 & done; wait
>> # watch: dmesg -w
>>
>> On a 112-CPU host this trips within ~2-5 minutes; this capture is
>> from 6.12.0-204.92.4.4.3.el9uek.x86_64:
>
> Awesome that you have a reproducer! Have you reproduced this on a mainline
> kernel? Enterprise kernels are not supported upstream.
I've been trying to reproduce the issue on v7.3.0-rc1 for half an hour
now with Ayush's reproducer, but haven't been able to trigger it.
prev parent reply other threads:[~2026-09-24 9:30 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-24 6:16 Ayush Ranjan
2026-09-24 7:12 ` David Hildenbrand (Arm)
2026-09-24 8:34 ` Pedro Falcato
2026-09-24 9:15 ` Jan Kara
2026-09-24 9:30 ` Baolin Wang [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=61f8a9af-7cdc-4979-bcc0-bcc932f7301f@linux.alibaba.com \
--to=baolin.wang@linux.alibaba.com \
--cc=akpm@linux-foundation.org \
--cc=ayushr@modal.com \
--cc=david@kernel.org \
--cc=gourry@gourry.net \
--cc=hughd@google.com \
--cc=jack@suse.cz \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=pfalcato@suse.de \
--cc=willy@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®