Re: [PATCH 03/13] mm: cachestat: restart the walk after each entry
From: Nhat Pham
Date: Thu Nov 12 2026 - 07:35:58 EST
On Wed, Nov 11, 2026 at 11:14 AM Lorenzo Stoakes (ARM) <ljs@xxxxxxxxxx> wrote:
>
> From: Chris Mason <mason@xxxxxxxxxx>
>
> cachestat() can leave cached pages out of its counts. This happens if
> the entry that the call has just counted is replaced by a larger folio
> that starts in the same XArray slot.
>
> The issue is that filemap_cachestat() walks the page cache under the RCU
> read lock, so racing concurrent collapse/split is possible.
>
> Thus, an entry can be replaced immediately after the walk has returned
> it. When that happens, the next xas_find() skips the sibling entries that
> point to the slot of that entry, since ordinarily they belong to that
> entry.
>
> However a concurrent collapse_file() or __filemap_add_folio() (when
> replacing a shadow entry) can store a larger folio in the slot, in which
> case the sibling entries belong to the new folio and the walk still skips
> them.
>
> Consider:
>
> cachestat collapse
> ========= ========
> count a 64-page folio in slot 8
> store a 512-page folio in slot 8,
> with sibling entries in slots 9-15
> xas_find() starts at slot 8
> and skips slots 9-15
> /* 448 pages are never counted */
>
> Also consider:
>
> filemap_cachestat() __filemap_add_folio()
> =================== =====================
> counts the shadow entry in slot 0
> slot 0: a folio of 32 pages
> slots 1-31: siblings of slot 0
> xas_find() skips slots 1-31
> /* 31 pages are never counted */
>
> Essentially the fact that large folios might be present means we cannot
> safely continue the XArray walk, and must reset the iterator each time.
Hmmm, cachestat is inherently racy, for performance's sake.
OTOH, it does seem a bit silly to undercount purely because we race
with an operation that does not change the answer (collapse/split).
Johannes, how do you feel about this tradeoff?