diff options
Diffstat (limited to 'include/linux/swapops.h')
-rw-r--r-- | include/linux/swapops.h | 125 |
1 files changed, 75 insertions, 50 deletions
diff --git a/include/linux/swapops.h b/include/linux/swapops.h index 5907205c712c..d356ab4047f7 100644 --- a/include/linux/swapops.h +++ b/include/linux/swapops.h @@ -107,10 +107,14 @@ static inline void *swp_to_radix_entry(swp_entry_t entry) } #if IS_ENABLED(CONFIG_DEVICE_PRIVATE) -static inline swp_entry_t make_device_private_entry(struct page *page, bool write) +static inline swp_entry_t make_readable_device_private_entry(pgoff_t offset) { - return swp_entry(write ? SWP_DEVICE_WRITE : SWP_DEVICE_READ, - page_to_pfn(page)); + return swp_entry(SWP_DEVICE_READ, offset); +} + +static inline swp_entry_t make_writable_device_private_entry(pgoff_t offset) +{ + return swp_entry(SWP_DEVICE_WRITE, offset); } static inline bool is_device_private_entry(swp_entry_t entry) @@ -119,33 +123,40 @@ static inline bool is_device_private_entry(swp_entry_t entry) return type == SWP_DEVICE_READ || type == SWP_DEVICE_WRITE; } -static inline void make_device_private_entry_read(swp_entry_t *entry) +static inline bool is_writable_device_private_entry(swp_entry_t entry) { - *entry = swp_entry(SWP_DEVICE_READ, swp_offset(*entry)); + return unlikely(swp_type(entry) == SWP_DEVICE_WRITE); } -static inline bool is_write_device_private_entry(swp_entry_t entry) +static inline swp_entry_t make_readable_device_exclusive_entry(pgoff_t offset) { - return unlikely(swp_type(entry) == SWP_DEVICE_WRITE); + return swp_entry(SWP_DEVICE_EXCLUSIVE_READ, offset); } -static inline unsigned long device_private_entry_to_pfn(swp_entry_t entry) +static inline swp_entry_t make_writable_device_exclusive_entry(pgoff_t offset) { - return swp_offset(entry); + return swp_entry(SWP_DEVICE_EXCLUSIVE_WRITE, offset); +} + +static inline bool is_device_exclusive_entry(swp_entry_t entry) +{ + return swp_type(entry) == SWP_DEVICE_EXCLUSIVE_READ || + swp_type(entry) == SWP_DEVICE_EXCLUSIVE_WRITE; } -static inline struct page *device_private_entry_to_page(swp_entry_t entry) +static inline bool is_writable_device_exclusive_entry(swp_entry_t entry) { - return pfn_to_page(swp_offset(entry)); + return unlikely(swp_type(entry) == SWP_DEVICE_EXCLUSIVE_WRITE); } #else /* CONFIG_DEVICE_PRIVATE */ -static inline swp_entry_t make_device_private_entry(struct page *page, bool write) +static inline swp_entry_t make_readable_device_private_entry(pgoff_t offset) { return swp_entry(0, 0); } -static inline void make_device_private_entry_read(swp_entry_t *entry) +static inline swp_entry_t make_writable_device_private_entry(pgoff_t offset) { + return swp_entry(0, 0); } static inline bool is_device_private_entry(swp_entry_t entry) @@ -153,61 +164,52 @@ static inline bool is_device_private_entry(swp_entry_t entry) return false; } -static inline bool is_write_device_private_entry(swp_entry_t entry) +static inline bool is_writable_device_private_entry(swp_entry_t entry) { return false; } -static inline unsigned long device_private_entry_to_pfn(swp_entry_t entry) +static inline swp_entry_t make_readable_device_exclusive_entry(pgoff_t offset) { - return 0; + return swp_entry(0, 0); } -static inline struct page *device_private_entry_to_page(swp_entry_t entry) +static inline swp_entry_t make_writable_device_exclusive_entry(pgoff_t offset) { - return NULL; + return swp_entry(0, 0); } -#endif /* CONFIG_DEVICE_PRIVATE */ -#ifdef CONFIG_MIGRATION -static inline swp_entry_t make_migration_entry(struct page *page, int write) +static inline bool is_device_exclusive_entry(swp_entry_t entry) { - BUG_ON(!PageLocked(compound_head(page))); + return false; +} - return swp_entry(write ? SWP_MIGRATION_WRITE : SWP_MIGRATION_READ, - page_to_pfn(page)); +static inline bool is_writable_device_exclusive_entry(swp_entry_t entry) +{ + return false; } +#endif /* CONFIG_DEVICE_PRIVATE */ +#ifdef CONFIG_MIGRATION static inline int is_migration_entry(swp_entry_t entry) { return unlikely(swp_type(entry) == SWP_MIGRATION_READ || swp_type(entry) == SWP_MIGRATION_WRITE); } -static inline int is_write_migration_entry(swp_entry_t entry) +static inline int is_writable_migration_entry(swp_entry_t entry) { return unlikely(swp_type(entry) == SWP_MIGRATION_WRITE); } -static inline unsigned long migration_entry_to_pfn(swp_entry_t entry) +static inline swp_entry_t make_readable_migration_entry(pgoff_t offset) { - return swp_offset(entry); + return swp_entry(SWP_MIGRATION_READ, offset); } -static inline struct page *migration_entry_to_page(swp_entry_t entry) +static inline swp_entry_t make_writable_migration_entry(pgoff_t offset) { - struct page *p = pfn_to_page(swp_offset(entry)); - /* - * Any use of migration entries may only occur while the - * corresponding page is locked - */ - BUG_ON(!PageLocked(compound_head(p))); - return p; -} - -static inline void make_migration_entry_read(swp_entry_t *entry) -{ - *entry = swp_entry(SWP_MIGRATION_READ, swp_offset(*entry)); + return swp_entry(SWP_MIGRATION_WRITE, offset); } extern void __migration_entry_wait(struct mm_struct *mm, pte_t *ptep, @@ -217,37 +219,58 @@ extern void migration_entry_wait(struct mm_struct *mm, pmd_t *pmd, extern void migration_entry_wait_huge(struct vm_area_struct *vma, struct mm_struct *mm, pte_t *pte); #else - -#define make_migration_entry(page, write) swp_entry(0, 0) -static inline int is_migration_entry(swp_entry_t swp) +static inline swp_entry_t make_readable_migration_entry(pgoff_t offset) { - return 0; + return swp_entry(0, 0); } -static inline unsigned long migration_entry_to_pfn(swp_entry_t entry) +static inline swp_entry_t make_writable_migration_entry(pgoff_t offset) { - return 0; + return swp_entry(0, 0); } -static inline struct page *migration_entry_to_page(swp_entry_t entry) +static inline int is_migration_entry(swp_entry_t swp) { - return NULL; + return 0; } -static inline void make_migration_entry_read(swp_entry_t *entryp) { } static inline void __migration_entry_wait(struct mm_struct *mm, pte_t *ptep, spinlock_t *ptl) { } static inline void migration_entry_wait(struct mm_struct *mm, pmd_t *pmd, unsigned long address) { } static inline void migration_entry_wait_huge(struct vm_area_struct *vma, struct mm_struct *mm, pte_t *pte) { } -static inline int is_write_migration_entry(swp_entry_t entry) +static inline int is_writable_migration_entry(swp_entry_t entry) { return 0; } #endif +static inline struct page *pfn_swap_entry_to_page(swp_entry_t entry) +{ + struct page *p = pfn_to_page(swp_offset(entry)); + + /* + * Any use of migration entries may only occur while the + * corresponding page is locked + */ + BUG_ON(is_migration_entry(entry) && !PageLocked(p)); + + return p; +} + +/* + * A pfn swap entry is a special type of swap entry that always has a pfn stored + * in the swap offset. They are used to represent unaddressable device memory + * and to restrict access to a page undergoing migration. + */ +static inline bool is_pfn_swap_entry(swp_entry_t entry) +{ + return is_migration_entry(entry) || is_device_private_entry(entry) || + is_device_exclusive_entry(entry); +} + struct page_vma_mapped_walk; #ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION @@ -265,6 +288,8 @@ static inline swp_entry_t pmd_to_swp_entry(pmd_t pmd) if (pmd_swp_soft_dirty(pmd)) pmd = pmd_swp_clear_soft_dirty(pmd); + if (pmd_swp_uffd_wp(pmd)) + pmd = pmd_swp_clear_uffd_wp(pmd); arch_entry = __pmd_to_swp_entry(pmd); return swp_entry(__swp_type(arch_entry), __swp_offset(arch_entry)); } |