[RFC PATCH 21/57] mm/collapse: settle whatever the round reached
From: Kiryl Shutsemau
Date: Sun Aug 16 2026 - 18:54:18 EST
From: "Kiryl Shutsemau (Meta)" <kas@xxxxxxxxxx>
Fill in the last pass. A candidate that never froze is recorded as given
up on, with whatever result ended the round. Anything no pass took
ownership of -- a destination folio, a table meant for deposit -- goes
back. The count of installed candidates is what the round reports.
Holding no lock here is the point. Every refusal before this happens
under a page-table lock: the freeze unwinds under the ptl it took, and
the install aborts under that ptl or the pmd lock.
Dropping the last reference to a folio, and the memcg uncharge behind it,
is not spinlock work. So a refused candidate keeps its folio and its
table until the round is over, and this is where they are released.
Assisted-by: Claude-Code:claude-opus-5
Signed-off-by: Kiryl Shutsemau (Meta) <kas@xxxxxxxxxx>
---
mm/collapse.c | 25 ++++++++++++++++++++++++-
1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/mm/collapse.c b/mm/collapse.c
index f65f413339bf..2da1f8ddcca8 100644
--- a/mm/collapse.c
+++ b/mm/collapse.c
@@ -1500,7 +1500,30 @@ static unsigned int collapse_finish(struct mm_struct *mm,
struct collapse_control *cc,
enum scan_result result)
{
- return 0;
+ unsigned int i, nr_installed = 0;
+
+ for (i = 0; i < cc->nr_candidates; i++) {
+ struct collapse_candidate *cand = &cc->candidates[i];
+
+ /* Never froze: the round gave up before it got that far */
+ if (cand->state == CAND_SELECTED) {
+ cand->state = CAND_SKIPPED;
+ cand->result = result;
+ }
+
+ if (cand->new_folio) {
+ folio_put(cand->new_folio);
+ cand->new_folio = NULL;
+ }
+ if (cand->deposit) {
+ pte_free(mm, cand->deposit);
+ cand->deposit = NULL;
+ }
+ if (cand->state == CAND_INSTALLED)
+ nr_installed++;
+ }
+
+ return nr_installed;
}
/*
--
2.54.0