Re: [PATCH] mm/gup: Drain batched mlock folio processing before attempting migration
From: David Hildenbrand
Date: Thu Aug 28 2025 - 04:59:39 EST
On 28.08.25 10:47, Hugh Dickins wrote:
On Sun, 24 Aug 2025, Hugh Dickins wrote:
On Mon, 18 Aug 2025, Will Deacon wrote:
On Mon, Aug 18, 2025 at 02:31:42PM +0100, Will Deacon wrote:
On Fri, Aug 15, 2025 at 09:14:48PM -0700, Hugh Dickins wrote:
I think replace the folio_test_mlocked(folio) part of it by
(folio_test_mlocked(folio) && !folio_test_unevictable(folio)).
That should reduce the extra calls to a much more reasonable
number, while still solving your issue.
Alas, I fear that the folio may be unevictable by this point (which
seems to coincide with the readahead fault adding it to the LRU above)
but I can try it out.
I gave this a spin but I still see failures with this change.
Many thanks, Will, for the precisely relevant traces (in which,
by the way, mapcount=0 really means _mapcount=0 hence mapcount=1).
Yes, those do indeed illustrate a case which my suggested
(folio_test_mlocked(folio) && !folio_test_unevictable(folio))
failed to cover. Very helpful to have an example of that.
And many thanks, David, for your reminder of commit 33dfe9204f29
("mm/gup: clear the LRU flag of a page before adding to LRU batch").
Yes, I strongly agree with your suggestion that the mlock batch
be brought into line with its change to the ordinary LRU batches,
and agree that doing so will be likely to solve Will's issue
(and similar cases elsewhere, without needing to modify them).
Now I just have to cool my head and get back down into those
mlock batches. I am fearful that making a change there to suit
this case will turn out later to break another case (and I just
won't have time to redevelop as thorough a grasp of the races as
I had back then). But if we're lucky, applying that "one batch
at a time" rule will actually make it all more comprehensible.
(I so wish we had spare room in struct page to keep the address
of that one batch entry, or the CPU to which that one batch
belongs: then, although that wouldn't eliminate all uses of
lru_add_drain_all(), it would allow us to efficiently extract
a target page from its LRU batch without a remote drain.)
I have not yet begun to write such a patch, and I'm not yet sure
that it's even feasible: this mail sent to get the polite thank
yous out of my mind, to help clear it for getting down to work.
It took several days in search of the least bad compromise, but
in the end I concluded the opposite of what we'd intended above.
There is a fundamental incompatibility between my 5.18 2fbb0c10d1e8
("mm/munlock: mlock_page() munlock_page() batch by pagevec")
and Ge Yang's 6.11 33dfe9204f29
("mm/gup: clear the LRU flag of a page before adding to LRU batch").
It turns out that the mm/swap.c folio batches (apart from lru_add)
are all for best-effort, doesn't matter if it's missed, operations;
whereas mlock and munlock are more serious. Probably mlock could
be (not very satisfactorily) converted, but then munlock? Because
of failed folio_test_clear_lru()s, it would be far too likely to
err on either side, munlocking too soon or too late.
I've concluded that one or the other has to go. If we're having
a beauty contest, there's no doubt that 33dfe9204f29 is much nicer
than 2fbb0c10d1e8 (which is itself far from perfect). But functionally,
I'm afraid that removing the mlock/munlock batching will show up as a
perceptible regression in realistic workloadsg; and on consideration,
I've found no real justification for the LRU flag clearing change.
Just to understand what you are saying: are you saying that we will go
back to having a folio being part of multiple LRU caches? :/ If so, I
really rally hope that we can find another way and not go back to that
old handling.
--
Cheers
David / dhildenb