0001
0002
0003
0004
0005
0006
0007
0008
0009 #ifndef _LINUX_USERFAULTFD_K_H
0010 #define _LINUX_USERFAULTFD_K_H
0011
0012 #ifdef CONFIG_USERFAULTFD
0013
0014 #include <linux/userfaultfd.h> /* linux/include/uapi/linux/userfaultfd.h */
0015
0016 #include <linux/fcntl.h>
0017 #include <linux/mm.h>
0018 #include <linux/swap.h>
0019 #include <linux/swapops.h>
0020 #include <asm-generic/pgtable_uffd.h>
0021 #include <linux/hugetlb_inline.h>
0022
0023
0024 #define __VM_UFFD_FLAGS (VM_UFFD_MISSING | VM_UFFD_WP | VM_UFFD_MINOR)
0025
0026
0027
0028
0029
0030
0031
0032
0033 #define UFFD_CLOEXEC O_CLOEXEC
0034 #define UFFD_NONBLOCK O_NONBLOCK
0035
0036 #define UFFD_SHARED_FCNTL_FLAGS (O_CLOEXEC | O_NONBLOCK)
0037 #define UFFD_FLAGS_SET (EFD_SHARED_FCNTL_FLAGS)
0038
0039 extern int sysctl_unprivileged_userfaultfd;
0040
0041 extern vm_fault_t handle_userfault(struct vm_fault *vmf, unsigned long reason);
0042
0043
0044
0045
0046
0047
0048
0049
0050 enum mcopy_atomic_mode {
0051
0052 MCOPY_ATOMIC_NORMAL,
0053
0054 MCOPY_ATOMIC_ZEROPAGE,
0055
0056 MCOPY_ATOMIC_CONTINUE,
0057 };
0058
0059 extern int mfill_atomic_install_pte(struct mm_struct *dst_mm, pmd_t *dst_pmd,
0060 struct vm_area_struct *dst_vma,
0061 unsigned long dst_addr, struct page *page,
0062 bool newly_allocated, bool wp_copy);
0063
0064 extern ssize_t mcopy_atomic(struct mm_struct *dst_mm, unsigned long dst_start,
0065 unsigned long src_start, unsigned long len,
0066 atomic_t *mmap_changing, __u64 mode);
0067 extern ssize_t mfill_zeropage(struct mm_struct *dst_mm,
0068 unsigned long dst_start,
0069 unsigned long len,
0070 atomic_t *mmap_changing);
0071 extern ssize_t mcopy_continue(struct mm_struct *dst_mm, unsigned long dst_start,
0072 unsigned long len, atomic_t *mmap_changing);
0073 extern int mwriteprotect_range(struct mm_struct *dst_mm,
0074 unsigned long start, unsigned long len,
0075 bool enable_wp, atomic_t *mmap_changing);
0076 extern void uffd_wp_range(struct mm_struct *dst_mm, struct vm_area_struct *vma,
0077 unsigned long start, unsigned long len, bool enable_wp);
0078
0079
0080 static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
0081 struct vm_userfaultfd_ctx vm_ctx)
0082 {
0083 return vma->vm_userfaultfd_ctx.ctx == vm_ctx.ctx;
0084 }
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097 static inline bool uffd_disable_huge_pmd_share(struct vm_area_struct *vma)
0098 {
0099 return vma->vm_flags & (VM_UFFD_WP | VM_UFFD_MINOR);
0100 }
0101
0102
0103
0104
0105
0106
0107
0108
0109 static inline bool uffd_disable_fault_around(struct vm_area_struct *vma)
0110 {
0111 return vma->vm_flags & (VM_UFFD_WP | VM_UFFD_MINOR);
0112 }
0113
0114 static inline bool userfaultfd_missing(struct vm_area_struct *vma)
0115 {
0116 return vma->vm_flags & VM_UFFD_MISSING;
0117 }
0118
0119 static inline bool userfaultfd_wp(struct vm_area_struct *vma)
0120 {
0121 return vma->vm_flags & VM_UFFD_WP;
0122 }
0123
0124 static inline bool userfaultfd_minor(struct vm_area_struct *vma)
0125 {
0126 return vma->vm_flags & VM_UFFD_MINOR;
0127 }
0128
0129 static inline bool userfaultfd_pte_wp(struct vm_area_struct *vma,
0130 pte_t pte)
0131 {
0132 return userfaultfd_wp(vma) && pte_uffd_wp(pte);
0133 }
0134
0135 static inline bool userfaultfd_huge_pmd_wp(struct vm_area_struct *vma,
0136 pmd_t pmd)
0137 {
0138 return userfaultfd_wp(vma) && pmd_uffd_wp(pmd);
0139 }
0140
0141 static inline bool userfaultfd_armed(struct vm_area_struct *vma)
0142 {
0143 return vma->vm_flags & __VM_UFFD_FLAGS;
0144 }
0145
0146 static inline bool vma_can_userfault(struct vm_area_struct *vma,
0147 unsigned long vm_flags)
0148 {
0149 if (vm_flags & VM_UFFD_MINOR)
0150 return is_vm_hugetlb_page(vma) || vma_is_shmem(vma);
0151
0152 #ifndef CONFIG_PTE_MARKER_UFFD_WP
0153
0154
0155
0156
0157
0158 if ((vm_flags & VM_UFFD_WP) && !vma_is_anonymous(vma))
0159 return false;
0160 #endif
0161 return vma_is_anonymous(vma) || is_vm_hugetlb_page(vma) ||
0162 vma_is_shmem(vma);
0163 }
0164
0165 extern int dup_userfaultfd(struct vm_area_struct *, struct list_head *);
0166 extern void dup_userfaultfd_complete(struct list_head *);
0167
0168 extern void mremap_userfaultfd_prep(struct vm_area_struct *,
0169 struct vm_userfaultfd_ctx *);
0170 extern void mremap_userfaultfd_complete(struct vm_userfaultfd_ctx *,
0171 unsigned long from, unsigned long to,
0172 unsigned long len);
0173
0174 extern bool userfaultfd_remove(struct vm_area_struct *vma,
0175 unsigned long start,
0176 unsigned long end);
0177
0178 extern int userfaultfd_unmap_prep(struct vm_area_struct *vma,
0179 unsigned long start, unsigned long end,
0180 struct list_head *uf);
0181 extern void userfaultfd_unmap_complete(struct mm_struct *mm,
0182 struct list_head *uf);
0183
0184 #else
0185
0186
0187 static inline vm_fault_t handle_userfault(struct vm_fault *vmf,
0188 unsigned long reason)
0189 {
0190 return VM_FAULT_SIGBUS;
0191 }
0192
0193 static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
0194 struct vm_userfaultfd_ctx vm_ctx)
0195 {
0196 return true;
0197 }
0198
0199 static inline bool userfaultfd_missing(struct vm_area_struct *vma)
0200 {
0201 return false;
0202 }
0203
0204 static inline bool userfaultfd_wp(struct vm_area_struct *vma)
0205 {
0206 return false;
0207 }
0208
0209 static inline bool userfaultfd_minor(struct vm_area_struct *vma)
0210 {
0211 return false;
0212 }
0213
0214 static inline bool userfaultfd_pte_wp(struct vm_area_struct *vma,
0215 pte_t pte)
0216 {
0217 return false;
0218 }
0219
0220 static inline bool userfaultfd_huge_pmd_wp(struct vm_area_struct *vma,
0221 pmd_t pmd)
0222 {
0223 return false;
0224 }
0225
0226
0227 static inline bool userfaultfd_armed(struct vm_area_struct *vma)
0228 {
0229 return false;
0230 }
0231
0232 static inline int dup_userfaultfd(struct vm_area_struct *vma,
0233 struct list_head *l)
0234 {
0235 return 0;
0236 }
0237
0238 static inline void dup_userfaultfd_complete(struct list_head *l)
0239 {
0240 }
0241
0242 static inline void mremap_userfaultfd_prep(struct vm_area_struct *vma,
0243 struct vm_userfaultfd_ctx *ctx)
0244 {
0245 }
0246
0247 static inline void mremap_userfaultfd_complete(struct vm_userfaultfd_ctx *ctx,
0248 unsigned long from,
0249 unsigned long to,
0250 unsigned long len)
0251 {
0252 }
0253
0254 static inline bool userfaultfd_remove(struct vm_area_struct *vma,
0255 unsigned long start,
0256 unsigned long end)
0257 {
0258 return true;
0259 }
0260
0261 static inline int userfaultfd_unmap_prep(struct vm_area_struct *vma,
0262 unsigned long start, unsigned long end,
0263 struct list_head *uf)
0264 {
0265 return 0;
0266 }
0267
0268 static inline void userfaultfd_unmap_complete(struct mm_struct *mm,
0269 struct list_head *uf)
0270 {
0271 }
0272
0273 static inline bool uffd_disable_fault_around(struct vm_area_struct *vma)
0274 {
0275 return false;
0276 }
0277
0278 #endif
0279
0280 static inline bool pte_marker_entry_uffd_wp(swp_entry_t entry)
0281 {
0282 #ifdef CONFIG_PTE_MARKER_UFFD_WP
0283 return is_pte_marker_entry(entry) &&
0284 (pte_marker_get(entry) & PTE_MARKER_UFFD_WP);
0285 #else
0286 return false;
0287 #endif
0288 }
0289
0290 static inline bool pte_marker_uffd_wp(pte_t pte)
0291 {
0292 #ifdef CONFIG_PTE_MARKER_UFFD_WP
0293 swp_entry_t entry;
0294
0295 if (!is_swap_pte(pte))
0296 return false;
0297
0298 entry = pte_to_swp_entry(pte);
0299
0300 return pte_marker_entry_uffd_wp(entry);
0301 #else
0302 return false;
0303 #endif
0304 }
0305
0306
0307
0308
0309
0310 static inline bool pte_swp_uffd_wp_any(pte_t pte)
0311 {
0312 #ifdef CONFIG_PTE_MARKER_UFFD_WP
0313 if (!is_swap_pte(pte))
0314 return false;
0315
0316 if (pte_swp_uffd_wp(pte))
0317 return true;
0318
0319 if (pte_marker_uffd_wp(pte))
0320 return true;
0321 #endif
0322 return false;
0323 }
0324
0325 #endif