From: "Kiryl Shutsemau (Meta)" <[email protected]>

Fill in the copy.  For each candidate that both froze and has a
destination folio, the page mapped at slot k of its window becomes page k
of that folio.  A slot with no source -- a hole, or a zeropage the freeze
cleared -- is zero-filled instead.

Neither condition implies the other.  A reserve before the lock can leave
a folio on a candidate that then fails to freeze, and the provision
inside the window can decline one for a candidate that froze.

Nothing else is carried across: the destination's PTE bits are not
derived from the sources, and the install rebuilds them the way a fault
would.

A machine check reading a source is the only failure the copy can report,
and only where the architecture provides an MC-safe copy.  The candidate
records SCAN_COPY_MC and the install undoes it, that being where the ptl
the undoing needs is held.

Assisted-by: Claude-Code:claude-opus-5
Signed-off-by: Kiryl Shutsemau (Meta) <[email protected]>
---
 mm/collapse.c | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/mm/collapse.c b/mm/collapse.c
index cf2b9b3640ae..a3882d897d11 100644
--- a/mm/collapse.c
+++ b/mm/collapse.c
@@ -1040,6 +1040,46 @@ static void collapse_provision(struct mm_struct *mm,
 static void collapse_copy(struct vm_area_struct *vma,
                          struct collapse_control *cc)
 {
+       unsigned int i;
+
+       for (i = 0; i < cc->nr_candidates; i++) {
+               struct collapse_candidate *cand = &cc->candidates[i];
+               const unsigned int nr_pages = candidate_nr_pages(cand);
+               unsigned long addr = cand->addr;
+               unsigned int k;
+
+               /* A folio does not imply a freeze: reserve runs before the 
lock */
+               if (cand->state != CAND_FROZEN)
+                       continue;
+
+               /* A freeze does not imply a folio: provision may have declined 
*/
+               if (!cand->new_folio)
+                       continue;
+
+               /* Each source lands where its address puts it: slot k, page k 
*/
+               for (k = 0; k < nr_pages; k++, addr += PAGE_SIZE) {
+                       struct page *dst = folio_page(cand->new_folio, k);
+                       struct page *src;
+
+                       /* No source: a hole, or a zeropage the freeze cleared 
*/
+                       if (pte_none_or_zero(cand->saved_ptes[k])) {
+                               clear_user_highpage(dst, addr);
+                               continue;
+                       }
+
+                       src = pte_page(cand->saved_ptes[k]);
+
+                       /*
+                        * A machine check on a source is the only way this
+                        * fails, and the install is what undoes the candidate:
+                        * that is where the ptl the undoing needs is held.
+                        */
+                       if (copy_mc_user_highpage(dst, src, addr, vma)) {
+                               cand->result = SCAN_COPY_MC;
+                               break;
+                       }
+               }
+       }
 }
 
 /* Publish each destination folio in place of the sources it replaces */
-- 
2.54.0


Reply via email to