| 1 |
|
| 2 | |
| 3 | * include/linux/userfaultfd_k.h
|
| 4 | *
|
| 5 | * Copyright (C) 2015 Red Hat, Inc.
|
| 6 | *
|
| 7 |
|
| 8 |
|
| 9 | #ifndef _LINUX_USERFAULTFD_K_H
|
| 10 | #define _LINUX_USERFAULTFD_K_H
|
| 11 |
|
| 12 | #ifdef CONFIG_USERFAULTFD
|
| 13 |
|
| 14 | #include <linux/userfaultfd.h>
|
| 15 |
|
| 16 | #include <linux/fcntl.h>
|
| 17 | #include <linux/mm.h>
|
| 18 | #include <linux/swap.h>
|
| 19 | #include <linux/leafops.h>
|
| 20 | #include <asm-generic/pgtable_uffd.h>
|
| 21 | #include <linux/hugetlb_inline.h>
|
| 22 |
|
| 23 |
|
| 24 | #define __VM_UFFD_FLAGS (VM_UFFD_MISSING | VM_UFFD_MINOR | \
|
| 25 | VM_UFFD_WP | VM_UFFD_RWP)
|
| 26 |
|
| 27 | #define __VMA_UFFD_FLAGS mk_vma_flags_from_masks(VMA_UFFD_MISSING, VMA_UFFD_WP, \
|
| 28 | VMA_UFFD_MINOR, VMA_UFFD_RWP)
|
| 29 |
|
| 30 | |
| 31 | * CAREFUL: Check include/uapi/asm-generic/fcntl.h when defining
|
| 32 | * new flags, since they might collide with O_* ones. We want
|
| 33 | * to re-use O_* flags that couldn't possibly have a meaning
|
| 34 | * from userfaultfd, in order to leave a free define-space for
|
| 35 | * shared O_* flags.
|
| 36 |
|
| 37 | #define UFFD_SHARED_FCNTL_FLAGS (O_CLOEXEC | O_NONBLOCK)
|
| 38 |
|
| 39 | |
| 40 | * Start with fault_pending_wqh and fault_wqh so they're more likely
|
| 41 | * to be in the same cacheline.
|
| 42 | *
|
| 43 | * Locking order:
|
| 44 | * fd_wqh.lock
|
| 45 | * fault_pending_wqh.lock
|
| 46 | * fault_wqh.lock
|
| 47 | * event_wqh.lock
|
| 48 | *
|
| 49 | * To avoid deadlocks, IRQs must be disabled when taking any of the above locks,
|
| 50 | * since fd_wqh.lock is taken by aio_poll() while it's holding a lock that's
|
| 51 | * also taken in IRQ context.
|
| 52 |
|
| 53 | struct userfaultfd_ctx {
|
| 54 |
|
| 55 | wait_queue_head_t fault_pending_wqh;
|
| 56 |
|
| 57 | wait_queue_head_t fault_wqh;
|
| 58 |
|
| 59 | wait_queue_head_t fd_wqh;
|
| 60 |
|
| 61 | wait_queue_head_t event_wqh;
|
| 62 |
|
| 63 | seqcount_spinlock_t refile_seq;
|
| 64 |
|
| 65 | refcount_t refcount;
|
| 66 |
|
| 67 | unsigned int flags;
|
| 68 |
|
| 69 | unsigned int features;
|
| 70 |
|
| 71 | bool released;
|
| 72 | |
| 73 | * Prevents userfaultfd operations (fill/move/wp) from happening while
|
| 74 | * some non-cooperative event(s) is taking place. Increments are done
|
| 75 | * in write-mode. Whereas, userfaultfd operations, which includes
|
| 76 | * reading mmap_changing, is done under read-mode.
|
| 77 |
|
| 78 | struct rw_semaphore map_changing_lock;
|
| 79 |
|
| 80 | atomic_t mmap_changing;
|
| 81 |
|
| 82 | struct mm_struct *mm;
|
| 83 | };
|
| 84 |
|
| 85 | extern vm_fault_t handle_userfault(struct vm_fault *vmf, unsigned long reason);
|
| 86 |
|
| 87 |
|
| 88 | struct vm_uffd_ops {
|
| 89 |
|
| 90 | bool (*can_userfault)(struct vm_area_struct *vma, vm_flags_t vm_flags);
|
| 91 | |
| 92 | * Called to resolve UFFDIO_CONTINUE request.
|
| 93 | * Should return the folio found at pgoff in the VMA's pagecache if it
|
| 94 | * exists or ERR_PTR otherwise.
|
| 95 | * The returned folio is locked and with reference held.
|
| 96 |
|
| 97 | struct folio *(*get_folio_noalloc)(struct inode *inode, pgoff_t pgoff);
|
| 98 | |
| 99 | * Called during resolution of UFFDIO_COPY request.
|
| 100 | * Should allocate and return a folio or NULL if allocation fails.
|
| 101 |
|
| 102 | struct folio *(*alloc_folio)(struct vm_area_struct *vma,
|
| 103 | unsigned long addr);
|
| 104 | |
| 105 | * Called during resolution of UFFDIO_COPY request.
|
| 106 | * Should only be called with a folio returned by alloc_folio() above.
|
| 107 | * The folio will be set to locked.
|
| 108 | * Returns 0 on success, error code on failure.
|
| 109 |
|
| 110 | int (*filemap_add)(struct folio *folio, struct vm_area_struct *vma,
|
| 111 | unsigned long addr);
|
| 112 | |
| 113 | * Called during resolution of UFFDIO_COPY request on the error
|
| 114 | * handling path.
|
| 115 | * Should revert the operation of ->filemap_add().
|
| 116 |
|
| 117 | void (*filemap_remove)(struct folio *folio, struct vm_area_struct *vma);
|
| 118 | };
|
| 119 |
|
| 120 |
|
| 121 | typedef unsigned int __bitwise uffd_flags_t;
|
| 122 |
|
| 123 |
|
| 124 | enum mfill_atomic_mode {
|
| 125 | MFILL_ATOMIC_COPY,
|
| 126 | MFILL_ATOMIC_ZEROPAGE,
|
| 127 | MFILL_ATOMIC_CONTINUE,
|
| 128 | MFILL_ATOMIC_POISON,
|
| 129 | NR_MFILL_ATOMIC_MODES,
|
| 130 | };
|
| 131 |
|
| 132 | #define MFILL_ATOMIC_MODE_BITS (const_ilog2(NR_MFILL_ATOMIC_MODES - 1) + 1)
|
| 133 | #define MFILL_ATOMIC_BIT(nr) BIT(MFILL_ATOMIC_MODE_BITS + (nr))
|
| 134 | #define MFILL_ATOMIC_FLAG(nr) ((__force uffd_flags_t) MFILL_ATOMIC_BIT(nr))
|
| 135 | #define MFILL_ATOMIC_MODE_MASK ((__force uffd_flags_t) (MFILL_ATOMIC_BIT(0) - 1))
|
| 136 |
|
| 137 | static inline bool uffd_flags_mode_is(uffd_flags_t flags, enum mfill_atomic_mode expected)
|
| 138 | {
|
| 139 | return (flags & MFILL_ATOMIC_MODE_MASK) == ((__force uffd_flags_t) expected);
|
| 140 | }
|
| 141 |
|
| 142 | static inline uffd_flags_t uffd_flags_set_mode(uffd_flags_t flags, enum mfill_atomic_mode mode)
|
| 143 | {
|
| 144 | flags &= ~MFILL_ATOMIC_MODE_MASK;
|
| 145 | return flags | ((__force uffd_flags_t) mode);
|
| 146 | }
|
| 147 |
|
| 148 |
|
| 149 | #define MFILL_ATOMIC_WP MFILL_ATOMIC_FLAG(0)
|
| 150 |
|
| 151 | extern long uffd_wp_range(struct vm_area_struct *vma,
|
| 152 | unsigned long start, unsigned long len, bool enable_wp);
|
| 153 | extern int mrwprotect_range(struct userfaultfd_ctx *ctx, unsigned long start,
|
| 154 | unsigned long len, bool enable_rwp);
|
| 155 |
|
| 156 |
|
| 157 | void double_pt_lock(spinlock_t *ptl1, spinlock_t *ptl2);
|
| 158 | void double_pt_unlock(spinlock_t *ptl1, spinlock_t *ptl2);
|
| 159 | int move_pages_huge_pmd(struct mm_struct *mm, pmd_t *dst_pmd, pmd_t *src_pmd, pmd_t dst_pmdval,
|
| 160 | struct vm_area_struct *dst_vma,
|
| 161 | struct vm_area_struct *src_vma,
|
| 162 | unsigned long dst_addr, unsigned long src_addr);
|
| 163 |
|
| 164 |
|
| 165 | static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
|
| 166 | struct vm_userfaultfd_ctx vm_ctx)
|
| 167 | {
|
| 168 | return vma->vm_userfaultfd_ctx.ctx == vm_ctx.ctx;
|
| 169 | }
|
| 170 |
|
| 171 | |
| 172 | * Never enable huge pmd sharing on some uffd registered vmas:
|
| 173 | *
|
| 174 | * - VM_UFFD_WP and VM_UFFD_RWP VMAs, because the write protect / access
|
| 175 | * tracking information is per pgtable entry.
|
| 176 | *
|
| 177 | * - VM_UFFD_MINOR VMAs, because otherwise we would never get minor faults for
|
| 178 | * VMAs which share huge pmds. (If you have two mappings to the same
|
| 179 | * underlying pages, and fault in the non-UFFD-registered one with a write,
|
| 180 | * with huge pmd sharing this would *also* setup the second UFFD-registered
|
| 181 | * mapping, and we'd not get minor faults.)
|
| 182 |
|
| 183 | static inline bool uffd_disable_huge_pmd_share(struct vm_area_struct *vma)
|
| 184 | {
|
| 185 | return vma_test_any_mask(vma,
|
| 186 | mk_vma_flags_from_masks(VMA_UFFD_WP, VMA_UFFD_RWP,
|
| 187 | VMA_UFFD_MINOR));
|
| 188 | }
|
| 189 |
|
| 190 | |
| 191 | * Don't do fault around for WP, RWP or MINOR registered uffd range. For
|
| 192 | * MINOR registered range, fault around will be a total disaster and ptes can
|
| 193 | * be installed without notifications; for WP it should mostly be fine as long
|
| 194 | * as the fault around checks for pte_none() before the installation, however
|
| 195 | * to be super safe we just forbid it; for RWP, pre-faulted neighbours would
|
| 196 | * be indistinguishable from accessed pages in PAGEMAP_SCAN (PAGE_IS_ACCESSED)
|
| 197 | * and pollute the tracked working set, so each page must be populated by its
|
| 198 | * own fault.
|
| 199 |
|
| 200 | static inline bool uffd_disable_fault_around(struct vm_area_struct *vma)
|
| 201 | {
|
| 202 | return vma_test_any_mask(vma,
|
| 203 | mk_vma_flags_from_masks(VMA_UFFD_WP, VMA_UFFD_RWP,
|
| 204 | VMA_UFFD_MINOR));
|
| 205 | }
|
| 206 |
|
| 207 | static inline bool userfaultfd_missing(struct vm_area_struct *vma)
|
| 208 | {
|
| 209 | return vma_test_any_mask(vma, VMA_UFFD_MISSING);
|
| 210 | }
|
| 211 |
|
| 212 | static inline bool userfaultfd_wp(struct vm_area_struct *vma)
|
| 213 | {
|
| 214 | return vma_test_any_mask(vma, VMA_UFFD_WP);
|
| 215 | }
|
| 216 |
|
| 217 | static inline bool userfaultfd_minor(struct vm_area_struct *vma)
|
| 218 | {
|
| 219 | return vma_test_any_mask(vma, VMA_UFFD_MINOR);
|
| 220 | }
|
| 221 |
|
| 222 | static inline bool userfaultfd_rwp(struct vm_area_struct *vma)
|
| 223 | {
|
| 224 | |
| 225 | * Callers gate PAGE_NONE usage on this; PAGE_NONE is a BUILD_BUG()
|
| 226 | * without CONFIG_ARCH_HAS_PTE_PROTNONE, so fold to false.
|
| 227 |
|
| 228 | if (!IS_ENABLED(CONFIG_ARCH_HAS_PTE_PROTNONE))
|
| 229 | return false;
|
| 230 | return vma_test_single_mask(vma, VMA_UFFD_RWP);
|
| 231 | }
|
| 232 |
|
| 233 | static inline bool userfaultfd_protected(struct vm_area_struct *vma)
|
| 234 | {
|
| 235 | return userfaultfd_wp(vma) || userfaultfd_rwp(vma);
|
| 236 | }
|
| 237 |
|
| 238 | static inline bool userfaultfd_pte_wp(struct vm_area_struct *vma,
|
| 239 | pte_t pte)
|
| 240 | {
|
| 241 | return userfaultfd_wp(vma) && pte_uffd(pte);
|
| 242 | }
|
| 243 |
|
| 244 | static inline bool userfaultfd_huge_pmd_wp(struct vm_area_struct *vma,
|
| 245 | pmd_t pmd)
|
| 246 | {
|
| 247 | return userfaultfd_wp(vma) && pmd_uffd(pmd);
|
| 248 | }
|
| 249 |
|
| 250 | static inline bool userfaultfd_pte_rwp(struct vm_area_struct *vma,
|
| 251 | pte_t pte)
|
| 252 | {
|
| 253 | return userfaultfd_rwp(vma) && pte_uffd(pte);
|
| 254 | }
|
| 255 |
|
| 256 | static inline bool userfaultfd_huge_pmd_rwp(struct vm_area_struct *vma,
|
| 257 | pmd_t pmd)
|
| 258 | {
|
| 259 | return userfaultfd_rwp(vma) && pmd_uffd(pmd);
|
| 260 | }
|
| 261 |
|
| 262 | static inline bool userfaultfd_armed(struct vm_area_struct *vma)
|
| 263 | {
|
| 264 | return vma_test_any_mask(vma, __VMA_UFFD_FLAGS);
|
| 265 | }
|
| 266 |
|
| 267 | static inline bool vma_has_uffd_without_event_remap(struct vm_area_struct *vma)
|
| 268 | {
|
| 269 | struct userfaultfd_ctx *uffd_ctx = vma->vm_userfaultfd_ctx.ctx;
|
| 270 |
|
| 271 | return uffd_ctx && (uffd_ctx->features & UFFD_FEATURE_EVENT_REMAP) == 0;
|
| 272 | }
|
| 273 |
|
| 274 | extern int dup_userfaultfd(struct vm_area_struct *, struct list_head *);
|
| 275 | extern void dup_userfaultfd_complete(struct list_head *);
|
| 276 | void dup_userfaultfd_fail(struct list_head *);
|
| 277 |
|
| 278 | extern void mremap_userfaultfd_prep(struct vm_area_struct *,
|
| 279 | struct vm_userfaultfd_ctx *);
|
| 280 | extern void mremap_userfaultfd_complete(struct vm_userfaultfd_ctx *,
|
| 281 | unsigned long from, unsigned long to,
|
| 282 | unsigned long len);
|
| 283 | void mremap_userfaultfd_fail(struct vm_userfaultfd_ctx *);
|
| 284 |
|
| 285 | extern bool userfaultfd_remove(struct vm_area_struct *vma,
|
| 286 | unsigned long start,
|
| 287 | unsigned long end);
|
| 288 |
|
| 289 | extern int userfaultfd_unmap_prep(struct vm_area_struct *vma,
|
| 290 | unsigned long start, unsigned long end, struct list_head *uf);
|
| 291 | extern void userfaultfd_unmap_complete(struct mm_struct *mm,
|
| 292 | struct list_head *uf);
|
| 293 | extern bool userfaultfd_wp_unpopulated(struct vm_area_struct *vma);
|
| 294 | extern bool userfaultfd_wp_async(struct vm_area_struct *vma);
|
| 295 | extern bool userfaultfd_rwp_async(struct vm_area_struct *vma);
|
| 296 |
|
| 297 | static inline bool userfaultfd_wp_use_markers(struct vm_area_struct *vma)
|
| 298 | {
|
| 299 |
|
| 300 | if (!userfaultfd_wp(vma))
|
| 301 | return false;
|
| 302 |
|
| 303 |
|
| 304 | if (!vma_is_anonymous(vma))
|
| 305 | return true;
|
| 306 |
|
| 307 | |
| 308 | * Anonymous uffd-wp only needs the markers if WP_UNPOPULATED
|
| 309 | * enabled (to apply markers on zero pages).
|
| 310 |
|
| 311 | return userfaultfd_wp_unpopulated(vma);
|
| 312 | }
|
| 313 |
|
| 314 | |
| 315 | * Returns true if this swap pte carries uffd-tracked state in either
|
| 316 | * form (pte marker or a normal swap pte), false otherwise.
|
| 317 |
|
| 318 | static inline bool pte_swp_uffd_any(pte_t pte)
|
| 319 | {
|
| 320 | if (!uffd_supports_wp_marker())
|
| 321 | return false;
|
| 322 |
|
| 323 | if (pte_present(pte))
|
| 324 | return false;
|
| 325 |
|
| 326 | if (pte_swp_uffd(pte))
|
| 327 | return true;
|
| 328 |
|
| 329 | if (pte_is_uffd_wp_marker(pte))
|
| 330 | return true;
|
| 331 |
|
| 332 | return false;
|
| 333 | }
|
| 334 | #else
|
| 335 |
|
| 336 |
|
| 337 | static inline vm_fault_t handle_userfault(struct vm_fault *vmf,
|
| 338 | unsigned long reason)
|
| 339 | {
|
| 340 | return VM_FAULT_SIGBUS;
|
| 341 | }
|
| 342 |
|
| 343 | static inline long uffd_wp_range(struct vm_area_struct *vma,
|
| 344 | unsigned long start, unsigned long len,
|
| 345 | bool enable_wp)
|
| 346 | {
|
| 347 | return false;
|
| 348 | }
|
| 349 |
|
| 350 | static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
|
| 351 | struct vm_userfaultfd_ctx vm_ctx)
|
| 352 | {
|
| 353 | return true;
|
| 354 | }
|
| 355 |
|
| 356 | static inline bool userfaultfd_missing(struct vm_area_struct *vma)
|
| 357 | {
|
| 358 | return false;
|
| 359 | }
|
| 360 |
|
| 361 | static inline bool userfaultfd_wp(struct vm_area_struct *vma)
|
| 362 | {
|
| 363 | return false;
|
| 364 | }
|
| 365 |
|
| 366 | static inline bool userfaultfd_minor(struct vm_area_struct *vma)
|
| 367 | {
|
| 368 | return false;
|
| 369 | }
|
| 370 |
|
| 371 | static inline bool userfaultfd_rwp(struct vm_area_struct *vma)
|
| 372 | {
|
| 373 | return false;
|
| 374 | }
|
| 375 |
|
| 376 | static inline bool userfaultfd_protected(struct vm_area_struct *vma)
|
| 377 | {
|
| 378 | return false;
|
| 379 | }
|
| 380 |
|
| 381 | static inline bool userfaultfd_pte_wp(struct vm_area_struct *vma,
|
| 382 | pte_t pte)
|
| 383 | {
|
| 384 | return false;
|
| 385 | }
|
| 386 |
|
| 387 | static inline bool userfaultfd_huge_pmd_wp(struct vm_area_struct *vma,
|
| 388 | pmd_t pmd)
|
| 389 | {
|
| 390 | return false;
|
| 391 | }
|
| 392 |
|
| 393 | static inline bool userfaultfd_pte_rwp(struct vm_area_struct *vma,
|
| 394 | pte_t pte)
|
| 395 | {
|
| 396 | return false;
|
| 397 | }
|
| 398 |
|
| 399 | static inline bool userfaultfd_huge_pmd_rwp(struct vm_area_struct *vma,
|
| 400 | pmd_t pmd)
|
| 401 | {
|
| 402 | return false;
|
| 403 | }
|
| 404 |
|
| 405 | static inline bool userfaultfd_armed(struct vm_area_struct *vma)
|
| 406 | {
|
| 407 | return false;
|
| 408 | }
|
| 409 |
|
| 410 | static inline int dup_userfaultfd(struct vm_area_struct *vma,
|
| 411 | struct list_head *l)
|
| 412 | {
|
| 413 | return 0;
|
| 414 | }
|
| 415 |
|
| 416 | static inline void dup_userfaultfd_complete(struct list_head *l)
|
| 417 | {
|
| 418 | }
|
| 419 |
|
| 420 | static inline void dup_userfaultfd_fail(struct list_head *l)
|
| 421 | {
|
| 422 | }
|
| 423 |
|
| 424 | static inline void mremap_userfaultfd_prep(struct vm_area_struct *vma,
|
| 425 | struct vm_userfaultfd_ctx *ctx)
|
| 426 | {
|
| 427 | }
|
| 428 |
|
| 429 | static inline void mremap_userfaultfd_complete(struct vm_userfaultfd_ctx *ctx,
|
| 430 | unsigned long from,
|
| 431 | unsigned long to,
|
| 432 | unsigned long len)
|
| 433 | {
|
| 434 | }
|
| 435 |
|
| 436 | static inline void mremap_userfaultfd_fail(struct vm_userfaultfd_ctx *ctx)
|
| 437 | {
|
| 438 | }
|
| 439 |
|
| 440 | static inline bool userfaultfd_remove(struct vm_area_struct *vma,
|
| 441 | unsigned long start,
|
| 442 | unsigned long end)
|
| 443 | {
|
| 444 | return true;
|
| 445 | }
|
| 446 |
|
| 447 | static inline int userfaultfd_unmap_prep(struct vm_area_struct *vma,
|
| 448 | unsigned long start, unsigned long end,
|
| 449 | struct list_head *uf)
|
| 450 | {
|
| 451 | return 0;
|
| 452 | }
|
| 453 |
|
| 454 | static inline void userfaultfd_unmap_complete(struct mm_struct *mm,
|
| 455 | struct list_head *uf)
|
| 456 | {
|
| 457 | }
|
| 458 |
|
| 459 | static inline bool uffd_disable_fault_around(struct vm_area_struct *vma)
|
| 460 | {
|
| 461 | return false;
|
| 462 | }
|
| 463 |
|
| 464 | static inline bool userfaultfd_wp_unpopulated(struct vm_area_struct *vma)
|
| 465 | {
|
| 466 | return false;
|
| 467 | }
|
| 468 |
|
| 469 | static inline bool userfaultfd_wp_async(struct vm_area_struct *vma)
|
| 470 | {
|
| 471 | return false;
|
| 472 | }
|
| 473 |
|
| 474 | static inline bool userfaultfd_rwp_async(struct vm_area_struct *vma)
|
| 475 | {
|
| 476 | return false;
|
| 477 | }
|
| 478 |
|
| 479 | static inline bool vma_has_uffd_without_event_remap(struct vm_area_struct *vma)
|
| 480 | {
|
| 481 | return false;
|
| 482 | }
|
| 483 |
|
| 484 | static inline bool userfaultfd_wp_use_markers(struct vm_area_struct *vma)
|
| 485 | {
|
| 486 | return false;
|
| 487 | }
|
| 488 |
|
| 489 | |
| 490 | * Returns true if this swap pte carries uffd-tracked state in either
|
| 491 | * form (pte marker or a normal swap pte), false otherwise.
|
| 492 |
|
| 493 | static inline bool pte_swp_uffd_any(pte_t pte)
|
| 494 | {
|
| 495 | return false;
|
| 496 | }
|
| 497 | #endif
|
| 498 | #endif
|