#include <linux/page_idle.h>
 #include <linux/pagemap.h>
 #include <linux/rmap.h>
+#include <linux/swap.h>
+#include <linux/swapops.h>
 
 #include "ops-common.h"
 
 
 void damon_ptep_mkold(pte_t *pte, struct vm_area_struct *vma, unsigned long addr)
 {
-       struct folio *folio = damon_get_folio(pte_pfn(ptep_get(pte)));
+       pte_t pteval = ptep_get(pte);
+       struct folio *folio;
+       bool young = false;
+       unsigned long pfn;
+
+       if (likely(pte_present(pteval)))
+               pfn = pte_pfn(pteval);
+       else
+               pfn = swp_offset_pfn(pte_to_swp_entry(pteval));
 
+       folio = damon_get_folio(pfn);
        if (!folio)
                return;
 
-       if (ptep_clear_young_notify(vma, addr, pte))
+       /*
+        * PFN swap PTEs, such as device-exclusive ones, that actually map pages
+        * are "old" from a CPU perspective. The MMU notifier takes care of any
+        * device aspects.
+        */
+       if (likely(pte_present(pteval)))
+               young |= ptep_test_and_clear_young(vma, addr, pte);
+       young |= mmu_notifier_clear_young(vma->vm_mm, addr, addr + PAGE_SIZE);
+       if (young)
                folio_set_young(folio);
 
        folio_set_idle(folio);