From: "Kiryl Shutsemau (Meta)" <[email protected]> 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) <[email protected]> --- 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
