| @@ -2284,7 +2284,7 @@ static const struct mm_walk_ops pagemap_ops = { · 2283 unmodified lines |
| 2284 | 2284 | * Bits 5-54 swap offset if swapped |
| 2285 | 2285 | * Bit 55 pte is soft-dirty (see Documentation/admin-guide/mm/soft-dirty.rst) |
| 2286 | 2286 | * Bit 56 page exclusively mapped |
| 2287 | | − * Bit 57 pte is uffd-wp write-protected |
| 2287 | + * Bit 57 pte is tracked by userfaultfd (uffd-wp or RWP) |
| 2288 | 2288 | * Bit 58 pte is a guard region |
| 2289 | 2289 | * Bits 59-60 zero |
| 2290 | 2290 | * Bit 61 page is file-page or shared-anon |
| @@ -2419,7 +2419,7 @@ static int pagemap_release(struct inode *inode, struct file *file) · 128 unmodified lines |
| 2419 | 2419 | PAGE_IS_FILE | PAGE_IS_PRESENT | \ |
| 2420 | 2420 | PAGE_IS_SWAPPED | PAGE_IS_PFNZERO | \ |
| 2421 | 2421 | PAGE_IS_HUGE | PAGE_IS_SOFT_DIRTY | \ |
| 2422 | | − PAGE_IS_GUARD) |
| 2422 | + PAGE_IS_GUARD | PAGE_IS_ACCESSED) |
| 2423 | 2423 | #define PM_SCAN_FLAGS (PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC) |
| 2424 | 2424 | |
| 2425 | 2425 | struct pagemap_scan_private { |
| @@ -2438,15 +2438,17 @@ static unsigned long pagemap_page_category(struct pagemap_scan_private *p, · 12 unmodified lines |
| 2438 | 2438 | |
| 2439 | 2439 | if (pte_none(pte)) { |
| 2440 | 2440 | /* |
| 2441 | | − * An unpopulated pte carries no uffd-wp marker, i.e. it is not |
| 2442 | | − * write-protected, the same condition under which the present |
| 2443 | | − * and swap cases below report PAGE_IS_WRITTEN. Report it here |
| 2444 | | − * too so this generic path agrees with the PAGE_IS_WRITTEN fast |
| 2445 | | − * path in pagemap_scan_pmd_entry(), which reports pte_none as |
| 2446 | | − * written and, under PM_SCAN_WP_MATCHING, arms a marker. The |
| 2447 | | − * fast path applies no VMA test, so neither does this. |
| 2441 | + * An unpopulated pte carries no uffd bit, i.e. it is not |
| 2442 | + * write-protected. The PAGE_IS_WRITTEN fast path in |
| 2443 | + * pagemap_scan_pmd_entry() is now gated on a VM_UFFD_WP VMA; |
| 2444 | + * gate the pte_none report here the same way so the two paths |
| 2445 | + * still agree. RWP has no such fast path and an unpopulated |
| 2446 | + * page is not part of the RWP working set, so it is reported as |
| 2447 | + * neither. |
| 2448 | 2448 | */ |
| 2449 | | − return PAGE_IS_WRITTEN; |
| 2449 | + if (userfaultfd_wp(vma)) |
| 2450 | + return PAGE_IS_WRITTEN; |
| 2451 | + return 0; |
| 2450 | 2452 | } |
| 2451 | 2453 | |
| 2452 | 2454 | if (pte_present(pte)) { |
| @@ -2454,8 +2456,12 @@ static unsigned long pagemap_page_category(struct pagemap_scan_private *p, · 1 unmodified line |
| 2454 | 2456 | |
| 2455 | 2457 | categories = PAGE_IS_PRESENT; |
| 2456 | 2458 | |
| 2457 | | − if (!pte_uffd(pte)) |
| 2458 | | − categories |= PAGE_IS_WRITTEN; |
| 2459 | + if (!pte_uffd(pte)) { |
| 2460 | + if (userfaultfd_wp(vma)) |
| 2461 | + categories |= PAGE_IS_WRITTEN; |
| 2462 | + if (userfaultfd_rwp(vma)) |
| 2463 | + categories |= PAGE_IS_ACCESSED; |
| 2464 | + } |
| 2459 | 2465 | |
| 2460 | 2466 | if (p->masks_of_interest & PAGE_IS_FILE) { |
| 2461 | 2467 | page = vm_normal_page(vma, addr, pte); |
| @@ -2472,8 +2478,12 @@ static unsigned long pagemap_page_category(struct pagemap_scan_private *p, · 10 unmodified lines |
| 2472 | 2478 | |
| 2473 | 2479 | categories = PAGE_IS_SWAPPED; |
| 2474 | 2480 | |
| 2475 | | − if (!pte_swp_uffd_any(pte)) |
| 2476 | | − categories |= PAGE_IS_WRITTEN; |
| 2481 | + if (!pte_swp_uffd_any(pte)) { |
| 2482 | + if (userfaultfd_wp(vma)) |
| 2483 | + categories |= PAGE_IS_WRITTEN; |
| 2484 | + if (userfaultfd_rwp(vma)) |
| 2485 | + categories |= PAGE_IS_ACCESSED; |
| 2486 | + } |
| 2477 | 2487 | |
| 2478 | 2488 | entry = softleaf_from_pte(pte); |
| 2479 | 2489 | if (softleaf_is_guard_marker(entry)) |
| @@ -2522,8 +2532,12 @@ static unsigned long pagemap_thp_category(struct pagemap_scan_private *p, · 42 unmodified lines |
| 2522 | 2532 | struct page *page; |
| 2523 | 2533 | |
| 2524 | 2534 | categories |= PAGE_IS_PRESENT; |
| 2525 | | − if (!pmd_uffd(pmd)) |
| 2526 | | − categories |= PAGE_IS_WRITTEN; |
| 2535 | + if (!pmd_uffd(pmd)) { |
| 2536 | + if (userfaultfd_wp(vma)) |
| 2537 | + categories |= PAGE_IS_WRITTEN; |
| 2538 | + if (userfaultfd_rwp(vma)) |
| 2539 | + categories |= PAGE_IS_ACCESSED; |
| 2540 | + } |
| 2527 | 2541 | |
| 2528 | 2542 | if (p->masks_of_interest & PAGE_IS_FILE) { |
| 2529 | 2543 | page = vm_normal_page_pmd(vma, addr, pmd); |
| @@ -2537,8 +2551,12 @@ static unsigned long pagemap_thp_category(struct pagemap_scan_private *p, · 7 unmodified lines |
| 2537 | 2551 | categories |= PAGE_IS_SOFT_DIRTY; |
| 2538 | 2552 | } else { |
| 2539 | 2553 | categories |= PAGE_IS_SWAPPED; |
| 2540 | | − if (!pmd_swp_uffd(pmd)) |
| 2541 | | − categories |= PAGE_IS_WRITTEN; |
| 2554 | + if (!pmd_swp_uffd(pmd)) { |
| 2555 | + if (userfaultfd_wp(vma)) |
| 2556 | + categories |= PAGE_IS_WRITTEN; |
| 2557 | + if (userfaultfd_rwp(vma)) |
| 2558 | + categories |= PAGE_IS_ACCESSED; |
| 2559 | + } |
| 2542 | 2560 | if (pmd_swp_soft_dirty(pmd)) |
| 2543 | 2561 | categories |= PAGE_IS_SOFT_DIRTY; |
| 2544 | 2562 | |
| @@ -2571,7 +2589,8 @@ static void make_uffd_wp_pmd(struct vm_area_struct *vma, · 26 unmodified lines |
| 2571 | 2589 | #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ |
| 2572 | 2590 | |
| 2573 | 2591 | #ifdef CONFIG_HUGETLB_PAGE |
| 2574 | | −static unsigned long pagemap_hugetlb_category(pte_t pte) |
| 2592 | +static unsigned long pagemap_hugetlb_category(struct vm_area_struct *vma, |
| 2593 | + pte_t pte) |
| 2575 | 2594 | { |
| 2576 | 2595 | unsigned long categories = PAGE_IS_HUGE; |
| 2577 | 2596 | |
| @@ -2586,8 +2605,12 @@ static unsigned long pagemap_hugetlb_category(pte_t pte) · 8 unmodified lines |
| 2586 | 2605 | if (pte_present(pte)) { |
| 2587 | 2606 | categories |= PAGE_IS_PRESENT; |
| 2588 | 2607 | |
| 2589 | | − if (!huge_pte_uffd(pte)) |
| 2590 | | − categories |= PAGE_IS_WRITTEN; |
| 2608 | + if (!huge_pte_uffd(pte)) { |
| 2609 | + if (userfaultfd_wp(vma)) |
| 2610 | + categories |= PAGE_IS_WRITTEN; |
| 2611 | + if (userfaultfd_rwp(vma)) |
| 2612 | + categories |= PAGE_IS_ACCESSED; |
| 2613 | + } |
| 2591 | 2614 | if (!PageAnon(pte_page(pte))) |
| 2592 | 2615 | categories |= PAGE_IS_FILE; |
| 2593 | 2616 | if (is_zero_pfn(pte_pfn(pte))) |
| @@ -2597,8 +2620,12 @@ static unsigned long pagemap_hugetlb_category(pte_t pte) · 3 unmodified lines |
| 2597 | 2620 | } else { |
| 2598 | 2621 | categories |= PAGE_IS_SWAPPED; |
| 2599 | 2622 | |
| 2600 | | − if (!pte_swp_uffd_any(pte)) |
| 2601 | | − categories |= PAGE_IS_WRITTEN; |
| 2623 | + if (!pte_swp_uffd_any(pte)) { |
| 2624 | + if (userfaultfd_wp(vma)) |
| 2625 | + categories |= PAGE_IS_WRITTEN; |
| 2626 | + if (userfaultfd_rwp(vma)) |
| 2627 | + categories |= PAGE_IS_ACCESSED; |
| 2628 | + } |
| 2602 | 2629 | if (pte_swp_soft_dirty(pte)) |
| 2603 | 2630 | categories |= PAGE_IS_SOFT_DIRTY; |
| 2604 | 2631 | } |
| @@ -2874,7 +2901,8 @@ static int pagemap_scan_pmd_entry(pmd_t *pmd, unsigned long start, · 269 unmodified lines |
| 2874 | 2901 | goto flush_and_return; |
| 2875 | 2902 | } |
| 2876 | 2903 | |
| 2877 | | − if (!p->arg.category_anyof_mask && !p->arg.category_inverted && |
| 2904 | + if (userfaultfd_wp(vma) && !p->arg.category_anyof_mask && |
| 2905 | + !p->arg.category_inverted && |
| 2878 | 2906 | p->arg.category_mask == PAGE_IS_WRITTEN && |
| 2879 | 2907 | p->arg.return_mask == PAGE_IS_WRITTEN) { |
| 2880 | 2908 | for (addr = start; addr < end; pte++, addr += PAGE_SIZE) { |
| @@ -2949,7 +2977,8 @@ static int pagemap_scan_hugetlb_entry(pte_t *ptep, unsigned long hmask, · 68 unmodified lines |
| 2949 | 2977 | /* Go the short route when not write-protecting pages. */ |
| 2950 | 2978 | |
| 2951 | 2979 | pte = huge_ptep_get(walk->mm, start, ptep); |
| 2952 | | − categories = p->cur_vma_category | pagemap_hugetlb_category(pte); |
| 2980 | + categories = p->cur_vma_category | |
| 2981 | + pagemap_hugetlb_category(vma, pte); |
| 2953 | 2982 | |
| 2954 | 2983 | if (!pagemap_scan_is_interesting_page(categories, p)) |
| 2955 | 2984 | return 0; |
| @@ -2961,7 +2990,7 @@ static int pagemap_scan_hugetlb_entry(pte_t *ptep, unsigned long hmask, · 5 unmodified lines |
| 2961 | 2990 | ptl = huge_pte_lock(hstate_vma(vma), vma->vm_mm, ptep); |
| 2962 | 2991 | |
| 2963 | 2992 | pte = huge_ptep_get(walk->mm, start, ptep); |
| 2964 | | − categories = p->cur_vma_category | pagemap_hugetlb_category(pte); |
| 2993 | + categories = p->cur_vma_category | pagemap_hugetlb_category(vma, pte); |
| 2965 | 2994 | |
| 2966 | 2995 | if (!pagemap_scan_is_interesting_page(categories, p)) |
| 2967 | 2996 | goto out_unlock; |