mprotect.c (692d42d411b7db6a76382537fccbee3a12a2bcdb) | mprotect.c (2bad466cc9d9b4c3b4b16eb9c03c919b59561316) |
---|---|
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * mm/mprotect.c 4 * 5 * (C) Copyright 1994 Linus Torvalds 6 * (C) Copyright 2002 Christoph Hellwig 7 * 8 * Address space accounting code <alan@lxorguk.ukuu.org.uk> --- 262 unchanged lines hidden (view full) --- 271 272 if (!pte_same(oldpte, newpte)) { 273 set_pte_at(vma->vm_mm, addr, pte, newpte); 274 pages++; 275 } 276 } else { 277 /* It must be an none page, or what else?.. */ 278 WARN_ON_ONCE(!pte_none(oldpte)); | 1// SPDX-License-Identifier: GPL-2.0 2/* 3 * mm/mprotect.c 4 * 5 * (C) Copyright 1994 Linus Torvalds 6 * (C) Copyright 2002 Christoph Hellwig 7 * 8 * Address space accounting code <alan@lxorguk.ukuu.org.uk> --- 262 unchanged lines hidden (view full) --- 271 272 if (!pte_same(oldpte, newpte)) { 273 set_pte_at(vma->vm_mm, addr, pte, newpte); 274 pages++; 275 } 276 } else { 277 /* It must be an none page, or what else?.. */ 278 WARN_ON_ONCE(!pte_none(oldpte)); |
279 if (unlikely(uffd_wp && !vma_is_anonymous(vma))) { | 279 280 /* 281 * Nobody plays with any none ptes besides 282 * userfaultfd when applying the protections. 283 */ 284 if (likely(!uffd_wp)) 285 continue; 286 287 if (userfaultfd_wp_use_markers(vma)) { |
280 /* 281 * For file-backed mem, we need to be able to 282 * wr-protect a none pte, because even if the 283 * pte is none, the page/swap cache could 284 * exist. Doing that by install a marker. 285 */ 286 set_pte_at(vma->vm_mm, addr, pte, 287 make_pte_marker(PTE_MARKER_UFFD_WP)); --- 27 unchanged lines hidden (view full) --- 315 if (unlikely(pmd_bad(pmdval))) { 316 pmd_clear_bad(pmd); 317 return 1; 318 } 319 320 return 0; 321} 322 | 288 /* 289 * For file-backed mem, we need to be able to 290 * wr-protect a none pte, because even if the 291 * pte is none, the page/swap cache could 292 * exist. Doing that by install a marker. 293 */ 294 set_pte_at(vma->vm_mm, addr, pte, 295 make_pte_marker(PTE_MARKER_UFFD_WP)); --- 27 unchanged lines hidden (view full) --- 323 if (unlikely(pmd_bad(pmdval))) { 324 pmd_clear_bad(pmd); 325 return 1; 326 } 327 328 return 0; 329} 330 |
323/* Return true if we're uffd wr-protecting file-backed memory, or false */ | 331/* 332 * Return true if we want to split THPs into PTE mappings in change 333 * protection procedure, false otherwise. 334 */ |
324static inline bool | 335static inline bool |
325uffd_wp_protect_file(struct vm_area_struct *vma, unsigned long cp_flags) | 336pgtable_split_needed(struct vm_area_struct *vma, unsigned long cp_flags) |
326{ | 337{ |
338 /* 339 * pte markers only resides in pte level, if we need pte markers, 340 * we need to split. We cannot wr-protect shmem thp because file 341 * thp is handled differently when split by erasing the pmd so far. 342 */ |
|
327 return (cp_flags & MM_CP_UFFD_WP) && !vma_is_anonymous(vma); 328} 329 330/* | 343 return (cp_flags & MM_CP_UFFD_WP) && !vma_is_anonymous(vma); 344} 345 346/* |
331 * If wr-protecting the range for file-backed, populate pgtable for the case 332 * when pgtable is empty but page cache exists. When {pte|pmd|...}_alloc() 333 * failed we treat it the same way as pgtable allocation failures during 334 * page faults by kicking OOM and returning error. | 347 * Return true if we want to populate pgtables in change protection 348 * procedure, false otherwise |
335 */ | 349 */ |
350static inline bool 351pgtable_populate_needed(struct vm_area_struct *vma, unsigned long cp_flags) 352{ 353 /* If not within ioctl(UFFDIO_WRITEPROTECT), then don't bother */ 354 if (!(cp_flags & MM_CP_UFFD_WP)) 355 return false; 356 357 /* Populate if the userfaultfd mode requires pte markers */ 358 return userfaultfd_wp_use_markers(vma); 359} 360 361/* 362 * Populate the pgtable underneath for whatever reason if requested. 363 * When {pte|pmd|...}_alloc() failed we treat it the same way as pgtable 364 * allocation failures during page faults by kicking OOM and returning 365 * error. 366 */ |
|
336#define change_pmd_prepare(vma, pmd, cp_flags) \ 337 ({ \ 338 long err = 0; \ | 367#define change_pmd_prepare(vma, pmd, cp_flags) \ 368 ({ \ 369 long err = 0; \ |
339 if (unlikely(uffd_wp_protect_file(vma, cp_flags))) { \ | 370 if (unlikely(pgtable_populate_needed(vma, cp_flags))) { \ |
340 if (pte_alloc(vma->vm_mm, pmd)) \ 341 err = -ENOMEM; \ 342 } \ 343 err; \ 344 }) 345 346/* 347 * This is the general pud/p4d/pgd version of change_pmd_prepare(). We need to 348 * have separate change_pmd_prepare() because pte_alloc() returns 0 on success, 349 * while {pmd|pud|p4d}_alloc() returns the valid pointer on success. 350 */ 351#define change_prepare(vma, high, low, addr, cp_flags) \ 352 ({ \ 353 long err = 0; \ | 371 if (pte_alloc(vma->vm_mm, pmd)) \ 372 err = -ENOMEM; \ 373 } \ 374 err; \ 375 }) 376 377/* 378 * This is the general pud/p4d/pgd version of change_pmd_prepare(). We need to 379 * have separate change_pmd_prepare() because pte_alloc() returns 0 on success, 380 * while {pmd|pud|p4d}_alloc() returns the valid pointer on success. 381 */ 382#define change_prepare(vma, high, low, addr, cp_flags) \ 383 ({ \ 384 long err = 0; \ |
354 if (unlikely(uffd_wp_protect_file(vma, cp_flags))) { \ | 385 if (unlikely(pgtable_populate_needed(vma, cp_flags))) { \ |
355 low##_t *p = low##_alloc(vma->vm_mm, high, addr); \ 356 if (p == NULL) \ 357 err = -ENOMEM; \ 358 } \ 359 err; \ 360 }) 361 362static inline long change_pmd_range(struct mmu_gather *tlb, --- 36 unchanged lines hidden (view full) --- 399 mmu_notifier_range_init(&range, 400 MMU_NOTIFY_PROTECTION_VMA, 0, 401 vma->vm_mm, addr, end); 402 mmu_notifier_invalidate_range_start(&range); 403 } 404 405 if (is_swap_pmd(*pmd) || pmd_trans_huge(*pmd) || pmd_devmap(*pmd)) { 406 if ((next - addr != HPAGE_PMD_SIZE) || | 386 low##_t *p = low##_alloc(vma->vm_mm, high, addr); \ 387 if (p == NULL) \ 388 err = -ENOMEM; \ 389 } \ 390 err; \ 391 }) 392 393static inline long change_pmd_range(struct mmu_gather *tlb, --- 36 unchanged lines hidden (view full) --- 430 mmu_notifier_range_init(&range, 431 MMU_NOTIFY_PROTECTION_VMA, 0, 432 vma->vm_mm, addr, end); 433 mmu_notifier_invalidate_range_start(&range); 434 } 435 436 if (is_swap_pmd(*pmd) || pmd_trans_huge(*pmd) || pmd_devmap(*pmd)) { 437 if ((next - addr != HPAGE_PMD_SIZE) || |
407 uffd_wp_protect_file(vma, cp_flags)) { | 438 pgtable_split_needed(vma, cp_flags)) { |
408 __split_huge_pmd(vma, pmd, addr, false, NULL); 409 /* 410 * For file-backed, the pmd could have been 411 * cleared; make sure pmd populated if 412 * necessary, then fall-through to pte level. 413 */ 414 ret = change_pmd_prepare(vma, pmd, cp_flags); 415 if (ret) { --- 493 unchanged lines hidden --- | 439 __split_huge_pmd(vma, pmd, addr, false, NULL); 440 /* 441 * For file-backed, the pmd could have been 442 * cleared; make sure pmd populated if 443 * necessary, then fall-through to pte level. 444 */ 445 ret = change_pmd_prepare(vma, pmd, cp_flags); 446 if (ret) { --- 493 unchanged lines hidden --- |