From: "Kiryl Shutsemau (Meta)" <[email protected]> A candidate a round attempts either collapsed or did not, and if it did not there is a reason. Selection needs those outcomes to decide what comes next: carry on past the window, try the same region at a lower order, or give the table up.
Fill in collapse_run_batch(): run the round, then walk the batch handing each candidate's result to classification. The walk covers the whole batch. A pass that refuses one candidate marks it and carries on rather than truncating the round, so every candidate has a result of its own to hand back. Only an outcome that condemns the table cuts the walk short, and then nothing of that table re-enters selection. The round and the classification it feeds are both stubs, so nothing is attempted and nothing is decided. Assisted-by: Claude-Code:claude-opus-5 Signed-off-by: Kiryl Shutsemau (Meta) <[email protected]> --- mm/collapse.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/mm/collapse.c b/mm/collapse.c index 6dae5e35e61d..ad9e5a447854 100644 --- a/mm/collapse.c +++ b/mm/collapse.c @@ -115,8 +115,16 @@ struct collapse_candidate { unsigned long addr; unsigned int order; + enum scan_result result; }; +/* Where a candidate sits in the table, in the PTE offsets selection counts in */ +static unsigned int candidate_offset(const struct collapse_candidate *cand, + unsigned long pmd_addr) +{ + return (cand->addr - pmd_addr) >> PAGE_SHIFT; +} + void collapse_control_release(struct collapse_control *cc) { kfree(cc->candidates); @@ -132,6 +140,17 @@ int collapse_control_init(struct collapse_control *cc) return 0; } +/* + * Carry one batch of candidates through the passes. Every candidate comes back + * with a result of its own: the passes before the freeze mark what they refuse + * and carry on, each pass after it works on what the last left, so no failure + * truncates the round. + */ +static void collapse_round(struct mm_struct *mm, unsigned long pmd_addr, + struct collapse_control *cc) +{ +} + /* * Is @count past a limit stated per PMD, when only part of a table was scanned? * Scale the comparison to the table so a partial scan is held to the same @@ -455,6 +474,18 @@ static bool collapse_next_candidate(struct collapse_control *cc, return false; } +/* + * Feed one candidate's outcome back into selection: its region is done, it + * re-enters the retry store at a lower order, or the table is abandoned. + * Returns false in that last case. + */ +static bool collapse_classify_result(struct collapse_control *cc, + unsigned int offset, unsigned int order, + enum scan_result result) +{ + return true; +} + /* * Run and classify the collected batch. Returns false when a candidate's * outcome abandons the table. @@ -462,9 +493,30 @@ static bool collapse_next_candidate(struct collapse_control *cc, static bool collapse_run_batch(struct mm_struct *mm, unsigned long pmd_addr, struct collapse_control *cc) { + unsigned int i; + /* collapse_anon_pmd() only runs a round it has put something in */ VM_WARN_ON_ONCE(!cc->nr_candidates); + collapse_round(mm, pmd_addr, cc); + + for (i = 0; i < cc->nr_candidates; i++) { + struct collapse_candidate *cand = &cc->candidates[i]; + unsigned int offset = candidate_offset(cand, pmd_addr); + + if (!collapse_classify_result(cc, offset, cand->order, + cand->result)) { + /* + * The table is abandoned: the candidates behind this one + * keep their results and are left unclassified, so + * nothing more of this table enters selection, and the + * abandoning result clears what earlier ones left there. + */ + cc->nr_candidates = 0; + return false; + } + } + cc->nr_candidates = 0; return true; } @@ -502,6 +554,7 @@ static void collapse_add_candidate(struct collapse_control *cc, cc->nr_candidates++; cand->addr = addr; cand->order = order; + cand->result = SCAN_FAIL; } /* -- 2.54.0
