11ad1335dSMike Rapoport============================= 21ad1335dSMike RapoportExamining Process Page Tables 31ad1335dSMike Rapoport============================= 41ad1335dSMike Rapoport 51ad1335dSMike Rapoportpagemap is a new (as of 2.6.25) set of interfaces in the kernel that allow 61ad1335dSMike Rapoportuserspace programs to examine the page tables and related information by 71ad1335dSMike Rapoportreading files in ``/proc``. 81ad1335dSMike Rapoport 91ad1335dSMike RapoportThere are four components to pagemap: 101ad1335dSMike Rapoport 111ad1335dSMike Rapoport * ``/proc/pid/pagemap``. This file lets a userspace process find out which 121ad1335dSMike Rapoport physical frame each virtual page is mapped to. It contains one 64-bit 131ad1335dSMike Rapoport value for each virtual page, containing the following data (from 141ad1335dSMike Rapoport ``fs/proc/task_mmu.c``, above pagemap_read): 151ad1335dSMike Rapoport 161ad1335dSMike Rapoport * Bits 0-54 page frame number (PFN) if present 171ad1335dSMike Rapoport * Bits 0-4 swap type if swapped 181ad1335dSMike Rapoport * Bits 5-54 swap offset if swapped 19e27a20f1SMike Rapoport * Bit 55 pte is soft-dirty (see 2000cba6b6SMike Rapoport (IBM) Documentation/admin-guide/mm/soft-dirty.rst) 211ad1335dSMike Rapoport * Bit 56 page exclusively mapped (since 4.2) 22fb8e37f3SPeter Xu * Bit 57 pte is uffd-wp write-protected (since 5.13) (see 2300cba6b6SMike Rapoport (IBM) Documentation/admin-guide/mm/userfaultfd.rst) 24dd21bfa4SYun Zhou * Bits 58-60 zero 251ad1335dSMike Rapoport * Bit 61 page is file-page or shared-anon (since 3.5) 261ad1335dSMike Rapoport * Bit 62 page swapped 271ad1335dSMike Rapoport * Bit 63 page present 281ad1335dSMike Rapoport 291ad1335dSMike Rapoport Since Linux 4.0 only users with the CAP_SYS_ADMIN capability can get PFNs. 301ad1335dSMike Rapoport In 4.0 and 4.1 opens by unprivileged fail with -EPERM. Starting from 311ad1335dSMike Rapoport 4.2 the PFN field is zeroed if the user does not have CAP_SYS_ADMIN. 321ad1335dSMike Rapoport Reason: information about PFNs helps in exploiting Rowhammer vulnerability. 331ad1335dSMike Rapoport 341ad1335dSMike Rapoport If the page is not present but in swap, then the PFN contains an 351ad1335dSMike Rapoport encoding of the swap file number and the page's offset into the 361ad1335dSMike Rapoport swap. Unmapped pages return a null PFN. This allows determining 371ad1335dSMike Rapoport precisely which pages are mapped (or in swap) and comparing mapped 381ad1335dSMike Rapoport pages between processes. 391ad1335dSMike Rapoport 401ad1335dSMike Rapoport Efficient users of this interface will use ``/proc/pid/maps`` to 411ad1335dSMike Rapoport determine which areas of memory are actually mapped and llseek to 421ad1335dSMike Rapoport skip over unmapped regions. 431ad1335dSMike Rapoport 441ad1335dSMike Rapoport * ``/proc/kpagecount``. This file contains a 64-bit count of the number of 451ad1335dSMike Rapoport times each page is mapped, indexed by PFN. 461ad1335dSMike Rapoport 47799fb82aSSeongJae ParkThe page-types tool in the tools/mm directory can be used to query the 487f1d23e6SChristian Hansennumber of times a page is mapped. 497f1d23e6SChristian Hansen 501ad1335dSMike Rapoport * ``/proc/kpageflags``. This file contains a 64-bit set of flags for each 511ad1335dSMike Rapoport page, indexed by PFN. 521ad1335dSMike Rapoport 531ad1335dSMike Rapoport The flags are (from ``fs/proc/page.c``, above kpageflags_read): 541ad1335dSMike Rapoport 551ad1335dSMike Rapoport 0. LOCKED 561ad1335dSMike Rapoport 1. ERROR 571ad1335dSMike Rapoport 2. REFERENCED 581ad1335dSMike Rapoport 3. UPTODATE 591ad1335dSMike Rapoport 4. DIRTY 601ad1335dSMike Rapoport 5. LRU 611ad1335dSMike Rapoport 6. ACTIVE 621ad1335dSMike Rapoport 7. SLAB 631ad1335dSMike Rapoport 8. WRITEBACK 641ad1335dSMike Rapoport 9. RECLAIM 651ad1335dSMike Rapoport 10. BUDDY 661ad1335dSMike Rapoport 11. MMAP 671ad1335dSMike Rapoport 12. ANON 681ad1335dSMike Rapoport 13. SWAPCACHE 691ad1335dSMike Rapoport 14. SWAPBACKED 701ad1335dSMike Rapoport 15. COMPOUND_HEAD 711ad1335dSMike Rapoport 16. COMPOUND_TAIL 721ad1335dSMike Rapoport 17. HUGE 731ad1335dSMike Rapoport 18. UNEVICTABLE 741ad1335dSMike Rapoport 19. HWPOISON 751ad1335dSMike Rapoport 20. NOPAGE 761ad1335dSMike Rapoport 21. KSM 771ad1335dSMike Rapoport 22. THP 78ca215086SDavid Hildenbrand 23. OFFLINE 791ad1335dSMike Rapoport 24. ZERO_PAGE 801ad1335dSMike Rapoport 25. IDLE 81ca215086SDavid Hildenbrand 26. PGTABLE 821ad1335dSMike Rapoport 831ad1335dSMike Rapoport * ``/proc/kpagecgroup``. This file contains a 64-bit inode number of the 841ad1335dSMike Rapoport memory cgroup each page is charged to, indexed by PFN. Only available when 851ad1335dSMike Rapoport CONFIG_MEMCG is set. 861ad1335dSMike Rapoport 871ad1335dSMike RapoportShort descriptions to the page flags 881ad1335dSMike Rapoport==================================== 891ad1335dSMike Rapoport 901ad1335dSMike Rapoport0 - LOCKED 910d16cfd4SSeongJae Park The page is being locked for exclusive access, e.g. by undergoing read/write 920d16cfd4SSeongJae Park IO. 931ad1335dSMike Rapoport7 - SLAB 94d88e2a2bSVlastimil Babka The page is managed by the SLAB/SLUB kernel memory allocator. 95d88e2a2bSVlastimil Babka When compound page is used, either will only set this flag on the head 96d88e2a2bSVlastimil Babka page. 971ad1335dSMike Rapoport10 - BUDDY 980d16cfd4SSeongJae Park A free memory block managed by the buddy system allocator. 991ad1335dSMike Rapoport The buddy system organizes free memory in blocks of various orders. 1001ad1335dSMike Rapoport An order N block has 2^N physically contiguous pages, with the BUDDY flag 1011ad1335dSMike Rapoport set for and _only_ for the first page. 1021ad1335dSMike Rapoport15 - COMPOUND_HEAD 1031ad1335dSMike Rapoport A compound page with order N consists of 2^N physically contiguous pages. 1041ad1335dSMike Rapoport A compound page with order 2 takes the form of "HTTT", where H donates its 1051ad1335dSMike Rapoport head page and T donates its tail page(s). The major consumers of compound 10600cba6b6SMike Rapoport (IBM) pages are hugeTLB pages (Documentation/admin-guide/mm/hugetlbpage.rst), 107e27a20f1SMike Rapoport the SLUB etc. memory allocators and various device drivers. 108e27a20f1SMike Rapoport However in this interface, only huge/giga pages are made visible 109e27a20f1SMike Rapoport to end users. 1101ad1335dSMike Rapoport16 - COMPOUND_TAIL 1111ad1335dSMike Rapoport A compound page tail (see description above). 1121ad1335dSMike Rapoport17 - HUGE 1130d16cfd4SSeongJae Park This is an integral part of a HugeTLB page. 1141ad1335dSMike Rapoport19 - HWPOISON 1150d16cfd4SSeongJae Park Hardware detected memory corruption on this page: don't touch the data! 1161ad1335dSMike Rapoport20 - NOPAGE 1170d16cfd4SSeongJae Park No page frame exists at the requested address. 1181ad1335dSMike Rapoport21 - KSM 1190d16cfd4SSeongJae Park Identical memory pages dynamically shared between one or more processes. 1201ad1335dSMike Rapoport22 - THP 1210d16cfd4SSeongJae Park Contiguous pages which construct transparent hugepages. 122ca215086SDavid Hildenbrand23 - OFFLINE 1230d16cfd4SSeongJae Park The page is logically offline. 1241ad1335dSMike Rapoport24 - ZERO_PAGE 1250d16cfd4SSeongJae Park Zero page for pfn_zero or huge_zero page. 1261ad1335dSMike Rapoport25 - IDLE 1270d16cfd4SSeongJae Park The page has not been accessed since it was marked idle (see 12800cba6b6SMike Rapoport (IBM) Documentation/admin-guide/mm/idle_page_tracking.rst). 129e27a20f1SMike Rapoport Note that this flag may be stale in case the page was accessed via 130e27a20f1SMike Rapoport a PTE. To make sure the flag is up-to-date one has to read 131e27a20f1SMike Rapoport ``/sys/kernel/mm/page_idle/bitmap`` first. 132ca215086SDavid Hildenbrand26 - PGTABLE 1330d16cfd4SSeongJae Park The page is in use as a page table. 1341ad1335dSMike Rapoport 1351ad1335dSMike RapoportIO related page flags 1361ad1335dSMike Rapoport--------------------- 1371ad1335dSMike Rapoport 1381ad1335dSMike Rapoport1 - ERROR 1390d16cfd4SSeongJae Park IO error occurred. 1401ad1335dSMike Rapoport3 - UPTODATE 1410d16cfd4SSeongJae Park The page has up-to-date data. 1421ad1335dSMike Rapoport ie. for file backed page: (in-memory data revision >= on-disk one) 1431ad1335dSMike Rapoport4 - DIRTY 1440d16cfd4SSeongJae Park The page has been written to, hence contains new data. 1451ad1335dSMike Rapoport i.e. for file backed page: (in-memory data revision > on-disk one) 1461ad1335dSMike Rapoport8 - WRITEBACK 1470d16cfd4SSeongJae Park The page is being synced to disk. 1481ad1335dSMike Rapoport 1491ad1335dSMike RapoportLRU related page flags 1501ad1335dSMike Rapoport---------------------- 1511ad1335dSMike Rapoport 1521ad1335dSMike Rapoport5 - LRU 1530d16cfd4SSeongJae Park The page is in one of the LRU lists. 1541ad1335dSMike Rapoport6 - ACTIVE 1550d16cfd4SSeongJae Park The page is in the active LRU list. 1561ad1335dSMike Rapoport18 - UNEVICTABLE 1570d16cfd4SSeongJae Park The page is in the unevictable (non-)LRU list It is somehow pinned and 1581ad1335dSMike Rapoport not a candidate for LRU page reclaims, e.g. ramfs pages, 1590d16cfd4SSeongJae Park shmctl(SHM_LOCK) and mlock() memory segments. 1601ad1335dSMike Rapoport2 - REFERENCED 1610d16cfd4SSeongJae Park The page has been referenced since last LRU list enqueue/requeue. 1621ad1335dSMike Rapoport9 - RECLAIM 1630d16cfd4SSeongJae Park The page will be reclaimed soon after its pageout IO completed. 1641ad1335dSMike Rapoport11 - MMAP 1650d16cfd4SSeongJae Park A memory mapped page. 1661ad1335dSMike Rapoport12 - ANON 1670d16cfd4SSeongJae Park A memory mapped page that is not part of a file. 1681ad1335dSMike Rapoport13 - SWAPCACHE 1690d16cfd4SSeongJae Park The page is mapped to swap space, i.e. has an associated swap entry. 1701ad1335dSMike Rapoport14 - SWAPBACKED 1710d16cfd4SSeongJae Park The page is backed by swap/RAM. 1721ad1335dSMike Rapoport 173799fb82aSSeongJae ParkThe page-types tool in the tools/mm directory can be used to query the 1741ad1335dSMike Rapoportabove flags. 1751ad1335dSMike Rapoport 1761ad1335dSMike RapoportUsing pagemap to do something useful 1771ad1335dSMike Rapoport==================================== 1781ad1335dSMike Rapoport 1791ad1335dSMike RapoportThe general procedure for using pagemap to find out about a process' memory 1801ad1335dSMike Rapoportusage goes like this: 1811ad1335dSMike Rapoport 1821ad1335dSMike Rapoport 1. Read ``/proc/pid/maps`` to determine which parts of the memory space are 1831ad1335dSMike Rapoport mapped to what. 1841ad1335dSMike Rapoport 2. Select the maps you are interested in -- all of them, or a particular 1851ad1335dSMike Rapoport library, or the stack or the heap, etc. 1861ad1335dSMike Rapoport 3. Open ``/proc/pid/pagemap`` and seek to the pages you would like to examine. 1871ad1335dSMike Rapoport 4. Read a u64 for each page from pagemap. 1881ad1335dSMike Rapoport 5. Open ``/proc/kpagecount`` and/or ``/proc/kpageflags``. For each PFN you 1891ad1335dSMike Rapoport just read, seek to that entry in the file, and read the data you want. 1901ad1335dSMike Rapoport 1911ad1335dSMike RapoportFor example, to find the "unique set size" (USS), which is the amount of 1921ad1335dSMike Rapoportmemory that a process is using that is not shared with any other process, 1931ad1335dSMike Rapoportyou can go through every map in the process, find the PFNs, look those up 1941ad1335dSMike Rapoportin kpagecount, and tally up the number of pages that are only referenced 1951ad1335dSMike Rapoportonce. 1961ad1335dSMike Rapoport 197cbbb69d3STiberiu A GeorgescuExceptions for Shared Memory 198cbbb69d3STiberiu A Georgescu============================ 199cbbb69d3STiberiu A Georgescu 200cbbb69d3STiberiu A GeorgescuPage table entries for shared pages are cleared when the pages are zapped or 201cbbb69d3STiberiu A Georgescuswapped out. This makes swapped out pages indistinguishable from never-allocated 202cbbb69d3STiberiu A Georgescuones. 203cbbb69d3STiberiu A Georgescu 204cbbb69d3STiberiu A GeorgescuIn kernel space, the swap location can still be retrieved from the page cache. 205cbbb69d3STiberiu A GeorgescuHowever, values stored only on the normal PTE get lost irretrievably when the 206cbbb69d3STiberiu A Georgescupage is swapped out (i.e. SOFT_DIRTY). 207cbbb69d3STiberiu A Georgescu 208cbbb69d3STiberiu A GeorgescuIn user space, whether the page is present, swapped or none can be deduced with 209cbbb69d3STiberiu A Georgescuthe help of lseek and/or mincore system calls. 210cbbb69d3STiberiu A Georgescu 211cbbb69d3STiberiu A Georgesculseek() can differentiate between accessed pages (present or swapped out) and 212cbbb69d3STiberiu A Georgescuholes (none/non-allocated) by specifying the SEEK_DATA flag on the file where 213cbbb69d3STiberiu A Georgescuthe pages are backed. For anonymous shared pages, the file can be found in 214cbbb69d3STiberiu A Georgescu``/proc/pid/map_files/``. 215cbbb69d3STiberiu A Georgescu 216cbbb69d3STiberiu A Georgescumincore() can differentiate between pages in memory (present, including swap 217cbbb69d3STiberiu A Georgescucache) and out of memory (swapped out or none/non-allocated). 218cbbb69d3STiberiu A Georgescu 2191ad1335dSMike RapoportOther notes 2201ad1335dSMike Rapoport=========== 2211ad1335dSMike Rapoport 2221ad1335dSMike RapoportReading from any of the files will return -EINVAL if you are not starting 2231ad1335dSMike Rapoportthe read on an 8-byte boundary (e.g., if you sought an odd number of bytes 2241ad1335dSMike Rapoportinto the file), or if the size of the read is not a multiple of 8 bytes. 2251ad1335dSMike Rapoport 2261ad1335dSMike RapoportBefore Linux 3.11 pagemap bits 55-60 were used for "page-shift" (which is 2271ad1335dSMike Rapoportalways 12 at most architectures). Since Linux 3.11 their meaning changes 2281ad1335dSMike Rapoportafter first clear of soft-dirty bits. Since Linux 4.2 they are used for 2291ad1335dSMike Rapoportflags unconditionally. 23018825b8aSMuhammad Usama Anjum 23118825b8aSMuhammad Usama AnjumPagemap Scan IOCTL 23218825b8aSMuhammad Usama Anjum================== 23318825b8aSMuhammad Usama Anjum 23418825b8aSMuhammad Usama AnjumThe ``PAGEMAP_SCAN`` IOCTL on the pagemap file can be used to get or optionally 23518825b8aSMuhammad Usama Anjumclear the info about page table entries. The following operations are supported 23618825b8aSMuhammad Usama Anjumin this IOCTL: 23718825b8aSMuhammad Usama Anjum 23818825b8aSMuhammad Usama Anjum- Scan the address range and get the memory ranges matching the provided criteria. 23918825b8aSMuhammad Usama Anjum This is performed when the output buffer is specified. 24018825b8aSMuhammad Usama Anjum- Write-protect the pages. The ``PM_SCAN_WP_MATCHING`` is used to write-protect 24118825b8aSMuhammad Usama Anjum the pages of interest. The ``PM_SCAN_CHECK_WPASYNC`` aborts the operation if 24218825b8aSMuhammad Usama Anjum non-Async Write Protected pages are found. The ``PM_SCAN_WP_MATCHING`` can be 24318825b8aSMuhammad Usama Anjum used with or without ``PM_SCAN_CHECK_WPASYNC``. 24418825b8aSMuhammad Usama Anjum- Both of those operations can be combined into one atomic operation where we can 24518825b8aSMuhammad Usama Anjum get and write protect the pages as well. 24618825b8aSMuhammad Usama Anjum 24718825b8aSMuhammad Usama AnjumFollowing flags about pages are currently supported: 24818825b8aSMuhammad Usama Anjum 24918825b8aSMuhammad Usama Anjum- ``PAGE_IS_WPALLOWED`` - Page has async-write-protection enabled 25018825b8aSMuhammad Usama Anjum- ``PAGE_IS_WRITTEN`` - Page has been written to from the time it was write protected 25118825b8aSMuhammad Usama Anjum- ``PAGE_IS_FILE`` - Page is file backed 25218825b8aSMuhammad Usama Anjum- ``PAGE_IS_PRESENT`` - Page is present in the memory 25318825b8aSMuhammad Usama Anjum- ``PAGE_IS_SWAPPED`` - Page is in swapped 25418825b8aSMuhammad Usama Anjum- ``PAGE_IS_PFNZERO`` - Page has zero PFN 25518825b8aSMuhammad Usama Anjum- ``PAGE_IS_HUGE`` - Page is THP or Hugetlb backed 256*e6a9a2cbSAndrei Vagin- ``PAGE_IS_SOFT_DIRTY`` - Page is soft-dirty 25718825b8aSMuhammad Usama Anjum 25818825b8aSMuhammad Usama AnjumThe ``struct pm_scan_arg`` is used as the argument of the IOCTL. 25918825b8aSMuhammad Usama Anjum 26018825b8aSMuhammad Usama Anjum 1. The size of the ``struct pm_scan_arg`` must be specified in the ``size`` 26118825b8aSMuhammad Usama Anjum field. This field will be helpful in recognizing the structure if extensions 26218825b8aSMuhammad Usama Anjum are done later. 26318825b8aSMuhammad Usama Anjum 2. The flags can be specified in the ``flags`` field. The ``PM_SCAN_WP_MATCHING`` 26418825b8aSMuhammad Usama Anjum and ``PM_SCAN_CHECK_WPASYNC`` are the only added flags at this time. The get 26518825b8aSMuhammad Usama Anjum operation is optionally performed depending upon if the output buffer is 26618825b8aSMuhammad Usama Anjum provided or not. 26718825b8aSMuhammad Usama Anjum 3. The range is specified through ``start`` and ``end``. 26818825b8aSMuhammad Usama Anjum 4. The walk can abort before visiting the complete range such as the user buffer 26918825b8aSMuhammad Usama Anjum can get full etc. The walk ending address is specified in``end_walk``. 27018825b8aSMuhammad Usama Anjum 5. The output buffer of ``struct page_region`` array and size is specified in 27118825b8aSMuhammad Usama Anjum ``vec`` and ``vec_len``. 27218825b8aSMuhammad Usama Anjum 6. The optional maximum requested pages are specified in the ``max_pages``. 27318825b8aSMuhammad Usama Anjum 7. The masks are specified in ``category_mask``, ``category_anyof_mask``, 27418825b8aSMuhammad Usama Anjum ``category_inverted`` and ``return_mask``. 27518825b8aSMuhammad Usama Anjum 27618825b8aSMuhammad Usama AnjumFind pages which have been written and WP them as well:: 27718825b8aSMuhammad Usama Anjum 27818825b8aSMuhammad Usama Anjum struct pm_scan_arg arg = { 27918825b8aSMuhammad Usama Anjum .size = sizeof(arg), 28018825b8aSMuhammad Usama Anjum .flags = PM_SCAN_CHECK_WPASYNC | PM_SCAN_CHECK_WPASYNC, 28118825b8aSMuhammad Usama Anjum .. 28218825b8aSMuhammad Usama Anjum .category_mask = PAGE_IS_WRITTEN, 28318825b8aSMuhammad Usama Anjum .return_mask = PAGE_IS_WRITTEN, 28418825b8aSMuhammad Usama Anjum }; 28518825b8aSMuhammad Usama Anjum 28618825b8aSMuhammad Usama AnjumFind pages which have been written, are file backed, not swapped and either 28718825b8aSMuhammad Usama Anjumpresent or huge:: 28818825b8aSMuhammad Usama Anjum 28918825b8aSMuhammad Usama Anjum struct pm_scan_arg arg = { 29018825b8aSMuhammad Usama Anjum .size = sizeof(arg), 29118825b8aSMuhammad Usama Anjum .flags = 0, 29218825b8aSMuhammad Usama Anjum .. 29318825b8aSMuhammad Usama Anjum .category_mask = PAGE_IS_WRITTEN | PAGE_IS_SWAPPED, 29418825b8aSMuhammad Usama Anjum .category_inverted = PAGE_IS_SWAPPED, 29518825b8aSMuhammad Usama Anjum .category_anyof_mask = PAGE_IS_PRESENT | PAGE_IS_HUGE, 29618825b8aSMuhammad Usama Anjum .return_mask = PAGE_IS_WRITTEN | PAGE_IS_SWAPPED | 29718825b8aSMuhammad Usama Anjum PAGE_IS_PRESENT | PAGE_IS_HUGE, 29818825b8aSMuhammad Usama Anjum }; 29918825b8aSMuhammad Usama Anjum 30018825b8aSMuhammad Usama AnjumThe ``PAGE_IS_WRITTEN`` flag can be considered as a better-performing alternative 30118825b8aSMuhammad Usama Anjumof soft-dirty flag. It doesn't get affected by VMA merging of the kernel and hence 30218825b8aSMuhammad Usama Anjumthe user can find the true soft-dirty pages in case of normal pages. (There may 30318825b8aSMuhammad Usama Anjumstill be extra dirty pages reported for THP or Hugetlb pages.) 30418825b8aSMuhammad Usama Anjum 30518825b8aSMuhammad Usama Anjum"PAGE_IS_WRITTEN" category is used with uffd write protect-enabled ranges to 30618825b8aSMuhammad Usama Anjumimplement memory dirty tracking in userspace: 30718825b8aSMuhammad Usama Anjum 30818825b8aSMuhammad Usama Anjum 1. The userfaultfd file descriptor is created with ``userfaultfd`` syscall. 30918825b8aSMuhammad Usama Anjum 2. The ``UFFD_FEATURE_WP_UNPOPULATED`` and ``UFFD_FEATURE_WP_ASYNC`` features 31018825b8aSMuhammad Usama Anjum are set by ``UFFDIO_API`` IOCTL. 31118825b8aSMuhammad Usama Anjum 3. The memory range is registered with ``UFFDIO_REGISTER_MODE_WP`` mode 31218825b8aSMuhammad Usama Anjum through ``UFFDIO_REGISTER`` IOCTL. 31318825b8aSMuhammad Usama Anjum 4. Then any part of the registered memory or the whole memory region must 31418825b8aSMuhammad Usama Anjum be write protected using ``PAGEMAP_SCAN`` IOCTL with flag ``PM_SCAN_WP_MATCHING`` 31518825b8aSMuhammad Usama Anjum or the ``UFFDIO_WRITEPROTECT`` IOCTL can be used. Both of these perform the 31618825b8aSMuhammad Usama Anjum same operation. The former is better in terms of performance. 31718825b8aSMuhammad Usama Anjum 5. Now the ``PAGEMAP_SCAN`` IOCTL can be used to either just find pages which 31818825b8aSMuhammad Usama Anjum have been written to since they were last marked and/or optionally write protect 31918825b8aSMuhammad Usama Anjum the pages as well. 320