This patch introduces a new swap entry type called PTE_MARKER. It can be installed for any pte that maps a file-backed memory when the pte is temporarily zapped, so as to maintain per-pte information. The information that kept in the pte is called a "marker". Here we define the marker as "unsigned long" just to match pgoff_t, however it will only work if it still fits in swp_offset(), which is e.g. currently 58 bits on x86_64. The first marker bit that is introduced together with the new swap pte is the PAGEOUT marker. When that bit is set, it means this pte used to point to a page which got swapped out. It's mostly a definition so the swap type is not totally nothing, however the functions are not implemented yet to handle the new swap type. A new config CONFIG_PTE_MARKER is introduced too; it's by default off. Signed-off-by: Peter Xu <peterx@xxxxxxxxxx> --- include/linux/swap.h | 14 ++++++++++++- include/linux/swapops.h | 45 +++++++++++++++++++++++++++++++++++++++++ mm/Kconfig | 17 ++++++++++++++++ 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/include/linux/swap.h b/include/linux/swap.h index 6f5a43251593..545dc8e0b0fb 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -55,6 +55,18 @@ static inline int current_is_kswapd(void) * actions on faults. */ +/* + * PTE markers are used to persist information onto PTEs that are mapped with + * file-backed memories. + */ +#ifdef CONFIG_PTE_MARKER +#define SWP_PTE_MARKER_NUM 1 +#define SWP_PTE_MARKER (MAX_SWAPFILES + SWP_HWPOISON_NUM + \ + SWP_MIGRATION_NUM + SWP_DEVICE_NUM) +#else +#define SWP_PTE_MARKER_NUM 0 +#endif + /* * Unaddressable device memory support. See include/linux/hmm.h and * Documentation/vm/hmm.rst. Short description is we need struct pages for @@ -100,7 +112,7 @@ static inline int current_is_kswapd(void) #define MAX_SWAPFILES \ ((1 << MAX_SWAPFILES_SHIFT) - SWP_DEVICE_NUM - \ - SWP_MIGRATION_NUM - SWP_HWPOISON_NUM) + SWP_MIGRATION_NUM - SWP_HWPOISON_NUM - SWP_PTE_MARKER_NUM) /* * Magic header for a swap area. The first part of the union is diff --git a/include/linux/swapops.h b/include/linux/swapops.h index d356ab4047f7..3fec83449e1e 100644 --- a/include/linux/swapops.h +++ b/include/linux/swapops.h @@ -247,6 +247,51 @@ static inline int is_writable_migration_entry(swp_entry_t entry) #endif +#ifdef CONFIG_PTE_MARKER + +#ifdef CONFIG_PTE_MARKER_PAGEOUT +/* When this bit is set, it means this page is swapped out previously */ +#define PTE_MARKER_PAGEOUT (1UL << 0) +#else +#define PTE_MARKER_PAGEOUT 0 +#endif + +#define PTE_MARKER_MASK (PTE_MARKER_PAGEOUT) + +static inline swp_entry_t make_pte_marker_entry(unsigned long marker) +{ + return swp_entry(SWP_PTE_MARKER, marker); +} + +static inline bool is_pte_marker_entry(swp_entry_t entry) +{ + return swp_type(entry) == SWP_PTE_MARKER; +} + +static inline unsigned long pte_marker_get(swp_entry_t entry) +{ + return swp_offset(entry) & PTE_MARKER_MASK; +} + +#else /* CONFIG_PTE_MARKER */ + +static inline swp_entry_t make_pte_marker_entry(unsigned long marker) +{ + return swp_entry(0, 0); +} + +static inline bool is_pte_marker_entry(swp_entry_t entry) +{ + return false; +} + +static inline unsigned long pte_marker_get(swp_entry_t entry) +{ + return 0; +} + +#endif /* CONFIG_PTE_MARKER */ + static inline struct page *pfn_swap_entry_to_page(swp_entry_t entry) { struct page *p = pfn_to_page(swp_offset(entry)); diff --git a/mm/Kconfig b/mm/Kconfig index 40a9bfcd5062..6043d8f1c066 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -889,4 +889,21 @@ config IO_MAPPING config SECRETMEM def_bool ARCH_HAS_SET_DIRECT_MAP && !EMBEDDED +config PTE_MARKER + def_bool n + bool "Marker PTEs support" + + help + Allows to create marker PTEs for file-backed memory. + +config PTE_MARKER_PAGEOUT + def_bool n + depends on PTE_MARKER + bool "Shmem pagemap PM_SWAP support" + + help + Allows to create marker PTEs for file-backed memory when the page is + swapped out. It's required for pagemap to work correctly with shmem + on page swapping. + endmenu -- 2.32.0