Pull misc hotfixes from Andrew Morton: "22 hotfixes. 13 are cc:stable and the remainder address post-6.14 issues or aren't considered necessary for -stable kernels. About half are for MM. Five OCFS2 fixes and a few MAINTAINERS updates" * tag 'mm-hotfixes-stable-2025-05-10-14-23' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm: (22 commits) mm: fix folio_pte_batch() on XEN PV nilfs2: fix deadlock warnings caused by lock dependency in init_nilfs() mm/hugetlb: copy the CMA flag when demoting mm, swap: fix false warning for large allocation with !THP_SWAP selftests/mm: fix a build failure on powerpc selftests/mm: fix build break when compiling pkey_util.c mm: vmalloc: support more granular vrealloc() sizing tools/testing/selftests: fix guard region test tmpfs assumption ocfs2: stop quota recovery before disabling quotas ocfs2: implement handshaking with ocfs2 recovery thread ocfs2: switch osb->disable_recovery to enum mailmap: map Uwe's BayLibre addresses to a single one MAINTAINERS: add mm THP section mm/userfaultfd: fix uninitialized output field for -EAGAIN race selftests/mm: compaction_test: support platform with huge mount of memory MAINTAINERS: add core mm section ocfs2: fix panic in failed foilio allocation mm/huge_memory: fix dereferencing invalid pmd migration entry MAINTAINERS: add reverse mapping section x86: disable image size check for test builds ...
Unified · Split
| @@ -447,6 +447,8 @@ Luca Ceresoli <luca.ceresoli@bootlin.com> <luca@lucaceresoli.net> · 446 unmodified lines | ||
| 447 | 447 | Luca Weiss <luca@lucaweiss.eu> <luca@z3ntu.xyz> |
| 448 | 448 | Lukasz Luba <lukasz.luba@arm.com> <l.luba@partner.samsung.com> |
| 449 | 449 | Luo Jie <quic_luoj@quicinc.com> <luoj@codeaurora.org> |
| 450 | +Lance Yang <lance.yang@linux.dev> <ioworker0@gmail.com> | |
| 451 | +Lance Yang <lance.yang@linux.dev> <mingzhe.yang@ly.com> | |
| 450 | 452 | Maciej W. Rozycki <macro@mips.com> <macro@imgtec.com> |
| 451 | 453 | Maciej W. Rozycki <macro@orcam.me.uk> <macro@linux-mips.org> |
| 452 | 454 | Maharaja Kennadyrajan <quic_mkenna@quicinc.com> <mkenna@codeaurora.org> |
| @@ -749,6 +751,7 @@ Tvrtko Ursulin <tursulin@ursulin.net> <tvrtko@ursulin.net> · 296 unmodified lines | ||
| 749 | 751 | Tycho Andersen <tycho@tycho.pizza> <tycho@tycho.ws> |
| 750 | 752 | Tzung-Bi Shih <tzungbi@kernel.org> <tzungbi@google.com> |
| 751 | 753 | Uwe Kleine-König <ukleinek@informatik.uni-freiburg.de> |
| 754 | +Uwe Kleine-König <u.kleine-koenig@baylibre.com> <ukleinek@baylibre.com> | |
| 752 | 755 | Uwe Kleine-König <u.kleine-koenig@pengutronix.de> |
| 753 | 756 | Uwe Kleine-König <ukleinek@strlen.de> |
| 754 | 757 | Uwe Kleine-König <ukl@pengutronix.de> |
| @@ -15495,24 +15495,45 @@ F: Documentation/mm/ · 15494 unmodified lines | ||
| 15495 | 15495 | F: include/linux/gfp.h |
| 15496 | 15496 | F: include/linux/gfp_types.h |
| 15497 | 15497 | F: include/linux/memfd.h |
| 15498 | −F: include/linux/memory.h | |
| 15499 | 15498 | F: include/linux/memory_hotplug.h |
| 15500 | 15499 | F: include/linux/memory-tiers.h |
| 15501 | 15500 | F: include/linux/mempolicy.h |
| 15502 | 15501 | F: include/linux/mempool.h |
| 15503 | 15502 | F: include/linux/memremap.h |
| 15504 | −F: include/linux/mm.h | |
| 15505 | −F: include/linux/mm_*.h | |
| 15506 | 15503 | F: include/linux/mmzone.h |
| 15507 | 15504 | F: include/linux/mmu_notifier.h |
| 15508 | 15505 | F: include/linux/pagewalk.h |
| 15509 | −F: include/linux/rmap.h | |
| 15510 | 15506 | F: include/trace/events/ksm.h |
| 15511 | 15507 | F: mm/ |
| 15512 | 15508 | F: tools/mm/ |
| 15513 | 15509 | F: tools/testing/selftests/mm/ |
| 15514 | 15510 | N: include/linux/page[-_]* |
| 15515 | 15511 | |
| 15512 | +MEMORY MANAGEMENT - CORE | |
| 15513 | +M: Andrew Morton <akpm@linux-foundation.org> | |
| 15514 | +M: David Hildenbrand <david@redhat.com> | |
| 15515 | +R: Lorenzo Stoakes <lorenzo.stoakes@oracle.com> | |
| 15516 | +R: Liam R. Howlett <Liam.Howlett@oracle.com> | |
| 15517 | +R: Vlastimil Babka <vbabka@suse.cz> | |
| 15518 | +R: Mike Rapoport <rppt@kernel.org> | |
| 15519 | +R: Suren Baghdasaryan <surenb@google.com> | |
| 15520 | +R: Michal Hocko <mhocko@suse.com> | |
| 15521 | +L: linux-mm@kvack.org | |
| 15522 | +S: Maintained | |
| 15523 | +W: http://www.linux-mm.org | |
| 15524 | +T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm | |
| 15525 | +F: include/linux/memory.h | |
| 15526 | +F: include/linux/mm.h | |
| 15527 | +F: include/linux/mm_*.h | |
| 15528 | +F: include/linux/mmdebug.h | |
| 15529 | +F: include/linux/pagewalk.h | |
| 15530 | +F: mm/Kconfig | |
| 15531 | +F: mm/debug.c | |
| 15532 | +F: mm/init-mm.c | |
| 15533 | +F: mm/memory.c | |
| 15534 | +F: mm/pagewalk.c | |
| 15535 | +F: mm/util.c | |
| 15536 | + | |
| 15516 | 15537 | MEMORY MANAGEMENT - EXECMEM |
| 15517 | 15538 | M: Andrew Morton <akpm@linux-foundation.org> |
| 15518 | 15539 | M: Mike Rapoport <rppt@kernel.org> |
| @@ -15546,6 +15567,19 @@ F: mm/page_alloc.c · 27 unmodified lines | ||
| 15546 | 15567 | F: include/linux/gfp.h |
| 15547 | 15568 | F: include/linux/compaction.h |
| 15548 | 15569 | |
| 15570 | +MEMORY MANAGEMENT - RMAP (REVERSE MAPPING) | |
| 15571 | +M: Andrew Morton <akpm@linux-foundation.org> | |
| 15572 | +M: David Hildenbrand <david@redhat.com> | |
| 15573 | +M: Lorenzo Stoakes <lorenzo.stoakes@oracle.com> | |
| 15574 | +R: Rik van Riel <riel@surriel.com> | |
| 15575 | +R: Liam R. Howlett <Liam.Howlett@oracle.com> | |
| 15576 | +R: Vlastimil Babka <vbabka@suse.cz> | |
| 15577 | +R: Harry Yoo <harry.yoo@oracle.com> | |
| 15578 | +L: linux-mm@kvack.org | |
| 15579 | +S: Maintained | |
| 15580 | +F: include/linux/rmap.h | |
| 15581 | +F: mm/rmap.c | |
| 15582 | + | |
| 15549 | 15583 | MEMORY MANAGEMENT - SECRETMEM |
| 15550 | 15584 | M: Andrew Morton <akpm@linux-foundation.org> |
| 15551 | 15585 | M: Mike Rapoport <rppt@kernel.org> |
| @@ -15554,6 +15588,30 @@ S: Maintained · 2 unmodified lines | ||
| 15554 | 15588 | F: include/linux/secretmem.h |
| 15555 | 15589 | F: mm/secretmem.c |
| 15556 | 15590 | |
| 15591 | +MEMORY MANAGEMENT - THP (TRANSPARENT HUGE PAGE) | |
| 15592 | +M: Andrew Morton <akpm@linux-foundation.org> | |
| 15593 | +M: David Hildenbrand <david@redhat.com> | |
| 15594 | +R: Zi Yan <ziy@nvidia.com> | |
| 15595 | +R: Baolin Wang <baolin.wang@linux.alibaba.com> | |
| 15596 | +R: Lorenzo Stoakes <lorenzo.stoakes@oracle.com> | |
| 15597 | +R: Liam R. Howlett <Liam.Howlett@oracle.com> | |
| 15598 | +R: Nico Pache <npache@redhat.com> | |
| 15599 | +R: Ryan Roberts <ryan.roberts@arm.com> | |
| 15600 | +R: Dev Jain <dev.jain@arm.com> | |
| 15601 | +L: linux-mm@kvack.org | |
| 15602 | +S: Maintained | |
| 15603 | +W: http://www.linux-mm.org | |
| 15604 | +T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm | |
| 15605 | +F: Documentation/admin-guide/mm/transhuge.rst | |
| 15606 | +F: include/linux/huge_mm.h | |
| 15607 | +F: include/linux/khugepaged.h | |
| 15608 | +F: include/trace/events/huge_memory.h | |
| 15609 | +F: mm/huge_memory.c | |
| 15610 | +F: mm/khugepaged.c | |
| 15611 | +F: tools/testing/selftests/mm/khugepaged.c | |
| 15612 | +F: tools/testing/selftests/mm/split_huge_page_test.c | |
| 15613 | +F: tools/testing/selftests/mm/transhuge-stress.c | |
| 15614 | + | |
| 15557 | 15615 | MEMORY MANAGEMENT - USERFAULTFD |
| 15558 | 15616 | M: Andrew Morton <akpm@linux-foundation.org> |
| 15559 | 15617 | R: Peter Xu <peterx@redhat.com> |
| @@ -466,10 +466,18 @@ SECTIONS · 465 unmodified lines | ||
| 466 | 466 | } |
| 467 | 467 | |
| 468 | 468 | /* |
| 469 | − * The ASSERT() sink to . is intentional, for binutils 2.14 compatibility: | |
| 469 | + * COMPILE_TEST kernels can be large - CONFIG_KASAN, for example, can cause | |
| 470 | + * this. Let's assume that nobody will be running a COMPILE_TEST kernel and | |
| 471 | + * let's assert that fuller build coverage is more valuable than being able to | |
| 472 | + * run a COMPILE_TEST kernel. | |
| 473 | + */ | |
| 474 | +#ifndef CONFIG_COMPILE_TEST | |
| 475 | +/* | |
| 476 | + * The ASSERT() sync to . is intentional, for binutils 2.14 compatibility: | |
| 470 | 477 | */ |
| 471 | 478 | . = ASSERT((_end - LOAD_OFFSET <= KERNEL_IMAGE_SIZE), |
| 472 | 479 | "kernel image bigger than KERNEL_IMAGE_SIZE"); |
| 480 | +#endif | |
| 473 | 481 | |
| 474 | 482 | /* needed for Clang - see arch/x86/entry/entry.S */ |
| 475 | 483 | PROVIDE(__ref_stack_chk_guard = __stack_chk_guard); |
| @@ -705,8 +705,6 @@ int init_nilfs(struct the_nilfs *nilfs, struct super_block *sb) · 704 unmodified lines | ||
| 705 | 705 | int blocksize; |
| 706 | 706 | int err; |
| 707 | 707 | |
| 708 | − down_write(&nilfs->ns_sem); | |
| 709 | − | |
| 710 | 708 | blocksize = sb_min_blocksize(sb, NILFS_MIN_BLOCK_SIZE); |
| 711 | 709 | if (!blocksize) { |
| 712 | 710 | nilfs_err(sb, "unable to set blocksize"); |
| @@ -779,7 +777,6 @@ int init_nilfs(struct the_nilfs *nilfs, struct super_block *sb) · 66 unmodified lines | ||
| 779 | 777 | set_nilfs_init(nilfs); |
| 780 | 778 | err = 0; |
| 781 | 779 | out: |
| 782 | − up_write(&nilfs->ns_sem); | |
| 783 | 780 | return err; |
| 784 | 781 | |
| 785 | 782 | failed_sbh: |
| @@ -6918,6 +6918,7 @@ static int ocfs2_grab_folios(struct inode *inode, loff_t start, loff_t end, · 6917 unmodified lines | ||
| 6918 | 6918 | if (IS_ERR(folios[numfolios])) { |
| 6919 | 6919 | ret = PTR_ERR(folios[numfolios]); |
| 6920 | 6920 | mlog_errno(ret); |
| 6921 | + folios[numfolios] = NULL; | |
| 6921 | 6922 | goto out; |
| 6922 | 6923 | } |
| 6923 | 6924 | |
| @@ -174,7 +174,7 @@ int ocfs2_recovery_init(struct ocfs2_super *osb) · 173 unmodified lines | ||
| 174 | 174 | struct ocfs2_recovery_map *rm; |
| 175 | 175 | |
| 176 | 176 | mutex_init(&osb->recovery_lock); |
| 177 | − osb->disable_recovery = 0; | |
| 177 | + osb->recovery_state = OCFS2_REC_ENABLED; | |
| 178 | 178 | osb->recovery_thread_task = NULL; |
| 179 | 179 | init_waitqueue_head(&osb->recovery_event); |
| 180 | 180 | |
| @@ -190,31 +190,53 @@ int ocfs2_recovery_init(struct ocfs2_super *osb) · 9 unmodified lines | ||
| 190 | 190 | return 0; |
| 191 | 191 | } |
| 192 | 192 | |
| 193 | −/* we can't grab the goofy sem lock from inside wait_event, so we use | |
| 194 | − * memory barriers to make sure that we'll see the null task before | |
| 195 | − * being woken up */ | |
| 196 | 193 | static int ocfs2_recovery_thread_running(struct ocfs2_super *osb) |
| 197 | 194 | { |
| 198 | − mb(); | |
| 199 | 195 | return osb->recovery_thread_task != NULL; |
| 200 | 196 | } |
| 201 | 197 | |
| 202 | −void ocfs2_recovery_exit(struct ocfs2_super *osb) | |
| 198 | +static void ocfs2_recovery_disable(struct ocfs2_super *osb, | |
| 199 | + enum ocfs2_recovery_state state) | |
| 203 | 200 | { |
| 204 | − struct ocfs2_recovery_map *rm; | |
| 205 | − | |
| 206 | − /* disable any new recovery threads and wait for any currently | |
| 207 | − * running ones to exit. Do this before setting the vol_state. */ | |
| 208 | 201 | mutex_lock(&osb->recovery_lock); |
| 209 | − osb->disable_recovery = 1; | |
| 202 | + /* | |
| 203 | + * If recovery thread is not running, we can directly transition to | |
| 204 | + * final state. | |
| 205 | + */ | |
| 206 | + if (!ocfs2_recovery_thread_running(osb)) { | |
| 207 | + osb->recovery_state = state + 1; | |
| 208 | + goto out_lock; | |
| 209 | + } | |
| 210 | + osb->recovery_state = state; | |
| 211 | + /* Wait for recovery thread to acknowledge state transition */ | |
| 212 | + wait_event_cmd(osb->recovery_event, | |
| 213 | + !ocfs2_recovery_thread_running(osb) || | |
| 214 | + osb->recovery_state >= state + 1, | |
| 215 | + mutex_unlock(&osb->recovery_lock), | |
| 216 | + mutex_lock(&osb->recovery_lock)); | |
| 217 | +out_lock: | |
| 210 | 218 | mutex_unlock(&osb->recovery_lock); |
| 211 | − wait_event(osb->recovery_event, !ocfs2_recovery_thread_running(osb)); | |
| 212 | 219 | |
| 213 | − /* At this point, we know that no more recovery threads can be | |
| 214 | − * launched, so wait for any recovery completion work to | |
| 215 | − * complete. */ | |
| 220 | + /* | |
| 221 | + * At this point we know that no more recovery work can be queued so | |
| 222 | + * wait for any recovery completion work to complete. | |
| 223 | + */ | |
| 216 | 224 | if (osb->ocfs2_wq) |
| 217 | 225 | flush_workqueue(osb->ocfs2_wq); |
| 226 | +} | |
| 227 | + | |
| 228 | +void ocfs2_recovery_disable_quota(struct ocfs2_super *osb) | |
| 229 | +{ | |
| 230 | + ocfs2_recovery_disable(osb, OCFS2_REC_QUOTA_WANT_DISABLE); | |
| 231 | +} | |
| 232 | + | |
| 233 | +void ocfs2_recovery_exit(struct ocfs2_super *osb) | |
| 234 | +{ | |
| 235 | + struct ocfs2_recovery_map *rm; | |
| 236 | + | |
| 237 | + /* disable any new recovery threads and wait for any currently | |
| 238 | + * running ones to exit. Do this before setting the vol_state. */ | |
| 239 | + ocfs2_recovery_disable(osb, OCFS2_REC_WANT_DISABLE); | |
| 218 | 240 | |
| 219 | 241 | /* |
| 220 | 242 | * Now that recovery is shut down, and the osb is about to be |
| @@ -1472,6 +1494,18 @@ static int __ocfs2_recovery_thread(void *arg) · 1251 unmodified lines | ||
| 1472 | 1494 | } |
| 1473 | 1495 | } |
| 1474 | 1496 | restart: |
| 1497 | + if (quota_enabled) { | |
| 1498 | + mutex_lock(&osb->recovery_lock); | |
| 1499 | + /* Confirm that recovery thread will no longer recover quotas */ | |
| 1500 | + if (osb->recovery_state == OCFS2_REC_QUOTA_WANT_DISABLE) { | |
| 1501 | + osb->recovery_state = OCFS2_REC_QUOTA_DISABLED; | |
| 1502 | + wake_up(&osb->recovery_event); | |
| 1503 | + } | |
| 1504 | + if (osb->recovery_state >= OCFS2_REC_QUOTA_DISABLED) | |
| 1505 | + quota_enabled = 0; | |
| 1506 | + mutex_unlock(&osb->recovery_lock); | |
| 1507 | + } | |
| 1508 | + | |
| 1475 | 1509 | status = ocfs2_super_lock(osb, 1); |
| 1476 | 1510 | if (status < 0) { |
| 1477 | 1511 | mlog_errno(status); |
| @@ -1569,27 +1603,29 @@ bail: · 91 unmodified lines | ||
| 1569 | 1603 | |
| 1570 | 1604 | ocfs2_free_replay_slots(osb); |
| 1571 | 1605 | osb->recovery_thread_task = NULL; |
| 1572 | − mb(); /* sync with ocfs2_recovery_thread_running */ | |
| 1606 | + if (osb->recovery_state == OCFS2_REC_WANT_DISABLE) | |
| 1607 | + osb->recovery_state = OCFS2_REC_DISABLED; | |
| 1573 | 1608 | wake_up(&osb->recovery_event); |
| 1574 | 1609 | |
| 1575 | 1610 | mutex_unlock(&osb->recovery_lock); |
| 1576 | 1611 | |
| 1577 | − if (quota_enabled) | |
| 1578 | − kfree(rm_quota); | |
| 1612 | + kfree(rm_quota); | |
| 1579 | 1613 | |
| 1580 | 1614 | return status; |
| 1581 | 1615 | } |
| 1582 | 1616 | |
| 1583 | 1617 | void ocfs2_recovery_thread(struct ocfs2_super *osb, int node_num) |
| 1584 | 1618 | { |
| 1619 | + int was_set = -1; | |
| 1620 | + | |
| 1585 | 1621 | mutex_lock(&osb->recovery_lock); |
| 1622 | + if (osb->recovery_state < OCFS2_REC_WANT_DISABLE) | |
| 1623 | + was_set = ocfs2_recovery_map_set(osb, node_num); | |
| 1586 | 1624 | |
| 1587 | 1625 | trace_ocfs2_recovery_thread(node_num, osb->node_num, |
| 1588 | − osb->disable_recovery, osb->recovery_thread_task, | |
| 1589 | − osb->disable_recovery ? | |
| 1590 | − -1 : ocfs2_recovery_map_set(osb, node_num)); | |
| 1626 | + osb->recovery_state, osb->recovery_thread_task, was_set); | |
| 1591 | 1627 | |
| 1592 | − if (osb->disable_recovery) | |
| 1628 | + if (osb->recovery_state >= OCFS2_REC_WANT_DISABLE) | |
| 1593 | 1629 | goto out; |
| 1594 | 1630 | |
| 1595 | 1631 | if (osb->recovery_thread_task) |
| @@ -148,6 +148,7 @@ void ocfs2_wait_for_recovery(struct ocfs2_super *osb); · 147 unmodified lines | ||
| 148 | 148 | |
| 149 | 149 | int ocfs2_recovery_init(struct ocfs2_super *osb); |
| 150 | 150 | void ocfs2_recovery_exit(struct ocfs2_super *osb); |
| 151 | +void ocfs2_recovery_disable_quota(struct ocfs2_super *osb); | |
| 151 | 152 | |
| 152 | 153 | int ocfs2_compute_replay_slots(struct ocfs2_super *osb); |
| 153 | 154 | void ocfs2_free_replay_slots(struct ocfs2_super *osb); |
| @@ -308,6 +308,21 @@ enum ocfs2_journal_trigger_type { · 307 unmodified lines | ||
| 308 | 308 | void ocfs2_initialize_journal_triggers(struct super_block *sb, |
| 309 | 309 | struct ocfs2_triggers triggers[]); |
| 310 | 310 | |
| 311 | +enum ocfs2_recovery_state { | |
| 312 | + OCFS2_REC_ENABLED = 0, | |
| 313 | + OCFS2_REC_QUOTA_WANT_DISABLE, | |
| 314 | + /* | |
| 315 | + * Must be OCFS2_REC_QUOTA_WANT_DISABLE + 1 for | |
| 316 | + * ocfs2_recovery_disable_quota() to work. | |
| 317 | + */ | |
| 318 | + OCFS2_REC_QUOTA_DISABLED, | |
| 319 | + OCFS2_REC_WANT_DISABLE, | |
| 320 | + /* | |
| 321 | + * Must be OCFS2_REC_WANT_DISABLE + 1 for ocfs2_recovery_exit() to work | |
| 322 | + */ | |
| 323 | + OCFS2_REC_DISABLED, | |
| 324 | +}; | |
| 325 | + | |
| 311 | 326 | struct ocfs2_journal; |
| 312 | 327 | struct ocfs2_slot_info; |
| 313 | 328 | struct ocfs2_recovery_map; |
| @@ -370,7 +385,7 @@ struct ocfs2_super · 56 unmodified lines | ||
| 370 | 385 | struct ocfs2_recovery_map *recovery_map; |
| 371 | 386 | struct ocfs2_replay_map *replay_map; |
| 372 | 387 | struct task_struct *recovery_thread_task; |
| 373 | − int disable_recovery; | |
| 388 | + enum ocfs2_recovery_state recovery_state; | |
| 374 | 389 | wait_queue_head_t checkpoint_event; |
| 375 | 390 | struct ocfs2_journal *journal; |
| 376 | 391 | unsigned long osb_commit_interval; |
| @@ -453,8 +453,7 @@ out: · 452 unmodified lines | ||
| 453 | 453 | |
| 454 | 454 | /* Sync changes in local quota file into global quota file and |
| 455 | 455 | * reinitialize local quota file. |
| 456 | − * The function expects local quota file to be already locked and | |
| 457 | − * s_umount locked in shared mode. */ | |
| 456 | + * The function expects local quota file to be already locked. */ | |
| 458 | 457 | static int ocfs2_recover_local_quota_file(struct inode *lqinode, |
| 459 | 458 | int type, |
| 460 | 459 | struct ocfs2_quota_recovery *rec) |
| @@ -588,7 +587,6 @@ int ocfs2_finish_quota_recovery(struct ocfs2_super *osb, · 127 unmodified lines | ||
| 588 | 587 | { |
| 589 | 588 | unsigned int ino[OCFS2_MAXQUOTAS] = { LOCAL_USER_QUOTA_SYSTEM_INODE, |
| 590 | 589 | LOCAL_GROUP_QUOTA_SYSTEM_INODE }; |
| 591 | − struct super_block *sb = osb->sb; | |
| 592 | 590 | struct ocfs2_local_disk_dqinfo *ldinfo; |
| 593 | 591 | struct buffer_head *bh; |
| 594 | 592 | handle_t *handle; |
| @@ -600,7 +598,6 @@ int ocfs2_finish_quota_recovery(struct ocfs2_super *osb, · 5 unmodified lines | ||
| 600 | 598 | printk(KERN_NOTICE "ocfs2: Finishing quota recovery on device (%s) for " |
| 601 | 599 | "slot %u\n", osb->dev_str, slot_num); |
| 602 | 600 | |
| 603 | − down_read(&sb->s_umount); | |
| 604 | 601 | for (type = 0; type < OCFS2_MAXQUOTAS; type++) { |
| 605 | 602 | if (list_empty(&(rec->r_list[type]))) |
| 606 | 603 | continue; |
| @@ -677,7 +674,6 @@ out_put: · 70 unmodified lines | ||
| 677 | 674 | break; |
| 678 | 675 | } |
| 679 | 676 | out: |
| 680 | − up_read(&sb->s_umount); | |
| 681 | 677 | kfree(rec); |
| 682 | 678 | return status; |
| 683 | 679 | } |
| @@ -843,8 +839,7 @@ static int ocfs2_local_free_info(struct super_block *sb, int type) · 159 unmodified lines | ||
| 843 | 839 | ocfs2_release_local_quota_bitmaps(&oinfo->dqi_chunk); |
| 844 | 840 | |
| 845 | 841 | /* |
| 846 | − * s_umount held in exclusive mode protects us against racing with | |
| 847 | − * recovery thread... | |
| 842 | + * ocfs2_dismount_volume() has already aborted quota recovery... | |
| 848 | 843 | */ |
| 849 | 844 | if (oinfo->dqi_rec) { |
| 850 | 845 | ocfs2_free_quota_recovery(oinfo->dqi_rec); |
| @@ -698,10 +698,12 @@ static int ocfs2_block_group_alloc(struct ocfs2_super *osb, · 697 unmodified lines | ||
| 698 | 698 | |
| 699 | 699 | bg_bh = ocfs2_block_group_alloc_contig(osb, handle, alloc_inode, |
| 700 | 700 | ac, cl); |
| 701 | − if (PTR_ERR(bg_bh) == -ENOSPC) | |
| 701 | + if (PTR_ERR(bg_bh) == -ENOSPC) { | |
| 702 | + ac->ac_which = OCFS2_AC_USE_MAIN_DISCONTIG; | |
| 702 | 703 | bg_bh = ocfs2_block_group_alloc_discontig(handle, |
| 703 | 704 | alloc_inode, |
| 704 | 705 | ac, cl); |
| 706 | + } | |
| 705 | 707 | if (IS_ERR(bg_bh)) { |
| 706 | 708 | status = PTR_ERR(bg_bh); |
| 707 | 709 | bg_bh = NULL; |
| @@ -1794,6 +1796,7 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac, · 1086 unmodified lines | ||
| 1794 | 1796 | { |
| 1795 | 1797 | int status; |
| 1796 | 1798 | u16 chain; |
| 1799 | + u32 contig_bits; | |
| 1797 | 1800 | u64 next_group; |
| 1798 | 1801 | struct inode *alloc_inode = ac->ac_inode; |
| 1799 | 1802 | struct buffer_head *group_bh = NULL; |
| @@ -1819,10 +1822,21 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac, · 19 unmodified lines | ||
| 1819 | 1822 | status = -ENOSPC; |
| 1820 | 1823 | /* for now, the chain search is a bit simplistic. We just use |
| 1821 | 1824 | * the 1st group with any empty bits. */ |
| 1822 | − while ((status = ac->ac_group_search(alloc_inode, group_bh, | |
| 1823 | − bits_wanted, min_bits, | |
| 1824 | − ac->ac_max_block, | |
| 1825 | − res)) == -ENOSPC) { | |
| 1825 | + while (1) { | |
| 1826 | + if (ac->ac_which == OCFS2_AC_USE_MAIN_DISCONTIG) { | |
| 1827 | + contig_bits = le16_to_cpu(bg->bg_contig_free_bits); | |
| 1828 | + if (!contig_bits) | |
| 1829 | + contig_bits = ocfs2_find_max_contig_free_bits(bg->bg_bitmap, | |
| 1830 | + le16_to_cpu(bg->bg_bits), 0); | |
| 1831 | + if (bits_wanted > contig_bits && contig_bits >= min_bits) | |
| 1832 | + bits_wanted = contig_bits; | |
| 1833 | + } | |
| 1834 | + | |
| 1835 | + status = ac->ac_group_search(alloc_inode, group_bh, | |
| 1836 | + bits_wanted, min_bits, | |
| 1837 | + ac->ac_max_block, res); | |
| 1838 | + if (status != -ENOSPC) | |
| 1839 | + break; | |
| 1826 | 1840 | if (!bg->bg_next_group) |
| 1827 | 1841 | break; |
| 1828 | 1842 | |
| @@ -1982,6 +1996,7 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac, · 153 unmodified lines | ||
| 1982 | 1996 | victim = ocfs2_find_victim_chain(cl); |
| 1983 | 1997 | ac->ac_chain = victim; |
| 1984 | 1998 | |
| 1999 | +search: | |
| 1985 | 2000 | status = ocfs2_search_chain(ac, handle, bits_wanted, min_bits, |
| 1986 | 2001 | res, &bits_left); |
| 1987 | 2002 | if (!status) { |
| @@ -2022,6 +2037,16 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac, · 34 unmodified lines | ||
| 2022 | 2037 | } |
| 2023 | 2038 | } |
| 2024 | 2039 | |
| 2040 | + /* Chains can't supply the bits_wanted contiguous space. | |
| 2041 | + * We should switch to using every single bit when allocating | |
| 2042 | + * from the global bitmap. */ | |
| 2043 | + if (i == le16_to_cpu(cl->cl_next_free_rec) && | |
| 2044 | + status == -ENOSPC && ac->ac_which == OCFS2_AC_USE_MAIN) { | |
| 2045 | + ac->ac_which = OCFS2_AC_USE_MAIN_DISCONTIG; | |
| 2046 | + ac->ac_chain = victim; | |
| 2047 | + goto search; | |
| 2048 | + } | |
| 2049 | + | |
| 2025 | 2050 | set_hint: |
| 2026 | 2051 | if (status != -ENOSPC) { |
| 2027 | 2052 | /* If the next search of this group is not likely to |
| @@ -2365,7 +2390,8 @@ int __ocfs2_claim_clusters(handle_t *handle, · 337 unmodified lines | ||
| 2365 | 2390 | BUG_ON(ac->ac_bits_given >= ac->ac_bits_wanted); |
| 2366 | 2391 | |
| 2367 | 2392 | BUG_ON(ac->ac_which != OCFS2_AC_USE_LOCAL |
| 2368 | − && ac->ac_which != OCFS2_AC_USE_MAIN); | |
| 2393 | + && ac->ac_which != OCFS2_AC_USE_MAIN | |
| 2394 | + && ac->ac_which != OCFS2_AC_USE_MAIN_DISCONTIG); | |
| 2369 | 2395 | |
| 2370 | 2396 | if (ac->ac_which == OCFS2_AC_USE_LOCAL) { |
| 2371 | 2397 | WARN_ON(min_clusters > 1); |
| @@ -29,6 +29,7 @@ struct ocfs2_alloc_context { · 28 unmodified lines | ||
| 29 | 29 | #define OCFS2_AC_USE_MAIN 2 |
| 30 | 30 | #define OCFS2_AC_USE_INODE 3 |
| 31 | 31 | #define OCFS2_AC_USE_META 4 |
| 32 | +#define OCFS2_AC_USE_MAIN_DISCONTIG 5 | |
| 32 | 33 | u32 ac_which; |
| 33 | 34 | |
| 34 | 35 | /* these are used by the chain search */ |
| @@ -1812,6 +1812,9 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err) · 1811 unmodified lines | ||
| 1812 | 1812 | /* Orphan scan should be stopped as early as possible */ |
| 1813 | 1813 | ocfs2_orphan_scan_stop(osb); |
| 1814 | 1814 | |
| 1815 | + /* Stop quota recovery so that we can disable quotas */ | |
| 1816 | + ocfs2_recovery_disable_quota(osb); | |
| 1817 | + | |
| 1815 | 1818 | ocfs2_disable_quotas(osb); |
| 1816 | 1819 | |
| 1817 | 1820 | /* All dquots should be freed by now */ |
| @@ -1585,8 +1585,11 @@ static int userfaultfd_copy(struct userfaultfd_ctx *ctx, · 1584 unmodified lines | ||
| 1585 | 1585 | user_uffdio_copy = (struct uffdio_copy __user *) arg; |
| 1586 | 1586 | |
| 1587 | 1587 | ret = -EAGAIN; |
| 1588 | − if (atomic_read(&ctx->mmap_changing)) | |
| 1588 | + if (unlikely(atomic_read(&ctx->mmap_changing))) { | |
| 1589 | + if (unlikely(put_user(ret, &user_uffdio_copy->copy))) | |
| 1590 | + return -EFAULT; | |
| 1589 | 1591 | goto out; |
| 1592 | + } | |
| 1590 | 1593 | |
| 1591 | 1594 | ret = -EFAULT; |
| 1592 | 1595 | if (copy_from_user(&uffdio_copy, user_uffdio_copy, |
| @@ -1641,8 +1644,11 @@ static int userfaultfd_zeropage(struct userfaultfd_ctx *ctx, · 48 unmodified lines | ||
| 1641 | 1644 | user_uffdio_zeropage = (struct uffdio_zeropage __user *) arg; |
| 1642 | 1645 | |
| 1643 | 1646 | ret = -EAGAIN; |
| 1644 | − if (atomic_read(&ctx->mmap_changing)) | |
| 1647 | + if (unlikely(atomic_read(&ctx->mmap_changing))) { | |
| 1648 | + if (unlikely(put_user(ret, &user_uffdio_zeropage->zeropage))) | |
| 1649 | + return -EFAULT; | |
| 1645 | 1650 | goto out; |
| 1651 | + } | |
| 1646 | 1652 | |
| 1647 | 1653 | ret = -EFAULT; |
| 1648 | 1654 | if (copy_from_user(&uffdio_zeropage, user_uffdio_zeropage, |
| @@ -1744,8 +1750,11 @@ static int userfaultfd_continue(struct userfaultfd_ctx *ctx, unsigned long arg) · 95 unmodified lines | ||
| 1744 | 1750 | user_uffdio_continue = (struct uffdio_continue __user *)arg; |
| 1745 | 1751 | |
| 1746 | 1752 | ret = -EAGAIN; |
| 1747 | − if (atomic_read(&ctx->mmap_changing)) | |
| 1753 | + if (unlikely(atomic_read(&ctx->mmap_changing))) { | |
| 1754 | + if (unlikely(put_user(ret, &user_uffdio_continue->mapped))) | |
| 1755 | + return -EFAULT; | |
| 1748 | 1756 | goto out; |
| 1757 | + } | |
| 1749 | 1758 | |
| 1750 | 1759 | ret = -EFAULT; |
| 1751 | 1760 | if (copy_from_user(&uffdio_continue, user_uffdio_continue, |
| @@ -1801,8 +1810,11 @@ static inline int userfaultfd_poison(struct userfaultfd_ctx *ctx, unsigned long · 49 unmodified lines | ||
| 1801 | 1810 | user_uffdio_poison = (struct uffdio_poison __user *)arg; |
| 1802 | 1811 | |
| 1803 | 1812 | ret = -EAGAIN; |
| 1804 | − if (atomic_read(&ctx->mmap_changing)) | |
| 1813 | + if (unlikely(atomic_read(&ctx->mmap_changing))) { | |
| 1814 | + if (unlikely(put_user(ret, &user_uffdio_poison->updated))) | |
| 1815 | + return -EFAULT; | |
| 1805 | 1816 | goto out; |
| 1817 | + } | |
| 1806 | 1818 | |
| 1807 | 1819 | ret = -EFAULT; |
| 1808 | 1820 | if (copy_from_user(&uffdio_poison, user_uffdio_poison, |
| @@ -1870,8 +1882,12 @@ static int userfaultfd_move(struct userfaultfd_ctx *ctx, · 61 unmodified lines | ||
| 1870 | 1882 | |
| 1871 | 1883 | user_uffdio_move = (struct uffdio_move __user *) arg; |
| 1872 | 1884 | |
| 1873 | − if (atomic_read(&ctx->mmap_changing)) | |
| 1874 | − return -EAGAIN; | |
| 1885 | + ret = -EAGAIN; | |
| 1886 | + if (unlikely(atomic_read(&ctx->mmap_changing))) { | |
| 1887 | + if (unlikely(put_user(ret, &user_uffdio_move->move))) | |
| 1888 | + return -EFAULT; | |
| 1889 | + goto out; | |
| 1890 | + } | |
| 1875 | 1891 | |
| 1876 | 1892 | if (copy_from_user(&uffdio_move, user_uffdio_move, |
| 1877 | 1893 | /* don't copy "move" last field */ |
| @@ -61,6 +61,7 @@ struct vm_struct { · 60 unmodified lines | ||
| 61 | 61 | unsigned int nr_pages; |
| 62 | 62 | phys_addr_t phys_addr; |
| 63 | 63 | const void *caller; |
| 64 | + unsigned long requested_size; | |
| 64 | 65 | }; |
| 65 | 66 | |
| 66 | 67 | struct vmap_area { |
| @@ -3075,6 +3075,8 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd, · 3074 unmodified lines | ||
| 3075 | 3075 | void split_huge_pmd_locked(struct vm_area_struct *vma, unsigned long address, |
| 3076 | 3076 | pmd_t *pmd, bool freeze, struct folio *folio) |
| 3077 | 3077 | { |
| 3078 | + bool pmd_migration = is_pmd_migration_entry(*pmd); | |
| 3079 | + | |
| 3078 | 3080 | VM_WARN_ON_ONCE(folio && !folio_test_pmd_mappable(folio)); |
| 3079 | 3081 | VM_WARN_ON_ONCE(!IS_ALIGNED(address, HPAGE_PMD_SIZE)); |
| 3080 | 3082 | VM_WARN_ON_ONCE(folio && !folio_test_locked(folio)); |
| @@ -3085,9 +3087,12 @@ void split_huge_pmd_locked(struct vm_area_struct *vma, unsigned long address, · 4 unmodified lines | ||
| 3085 | 3087 | * require a folio to check the PMD against. Otherwise, there |
| 3086 | 3088 | * is a risk of replacing the wrong folio. |
| 3087 | 3089 | */ |
| 3088 | − if (pmd_trans_huge(*pmd) || pmd_devmap(*pmd) || | |
| 3089 | − is_pmd_migration_entry(*pmd)) { | |
| 3090 | − if (folio && folio != pmd_folio(*pmd)) | |
| 3090 | + if (pmd_trans_huge(*pmd) || pmd_devmap(*pmd) || pmd_migration) { | |
| 3091 | + /* | |
| 3092 | + * Do not apply pmd_folio() to a migration entry; and folio lock | |
| 3093 | + * guarantees that it must be of the wrong folio anyway. | |
| 3094 | + */ | |
| 3095 | + if (folio && (pmd_migration || folio != pmd_folio(*pmd))) | |
| 3091 | 3096 | return; |
| 3092 | 3097 | __split_huge_pmd_locked(vma, pmd, address, freeze); |
| 3093 | 3098 | } |
| @@ -4034,10 +4034,13 @@ static long demote_free_hugetlb_folios(struct hstate *src, struct hstate *dst, · 4033 unmodified lines | ||
| 4034 | 4034 | |
| 4035 | 4035 | list_for_each_entry_safe(folio, next, src_list, lru) { |
| 4036 | 4036 | int i; |
| 4037 | + bool cma; | |
| 4037 | 4038 | |
| 4038 | 4039 | if (folio_test_hugetlb_vmemmap_optimized(folio)) |
| 4039 | 4040 | continue; |
| 4040 | 4041 | |
| 4042 | + cma = folio_test_hugetlb_cma(folio); | |
| 4043 | + | |
| 4041 | 4044 | list_del(&folio->lru); |
| 4042 | 4045 | |
| 4043 | 4046 | split_page_owner(&folio->page, huge_page_order(src), huge_page_order(dst)); |
| @@ -4053,6 +4056,9 @@ static long demote_free_hugetlb_folios(struct hstate *src, struct hstate *dst, · 9 unmodified lines | ||
| 4053 | 4056 | |
| 4054 | 4057 | new_folio->mapping = NULL; |
| 4055 | 4058 | init_new_hugetlb_folio(dst, new_folio); |
| 4059 | + /* Copy the CMA flag so that it is freed correctly */ | |
| 4060 | + if (cma) | |
| 4061 | + folio_set_hugetlb_cma(new_folio); | |
| 4056 | 4062 | list_add(&new_folio->lru, &dst_list); |
| 4057 | 4063 | } |
| 4058 | 4064 | } |
| @@ -248,11 +248,9 @@ static inline int folio_pte_batch(struct folio *folio, unsigned long addr, · 247 unmodified lines | ||
| 248 | 248 | pte_t *start_ptep, pte_t pte, int max_nr, fpb_t flags, |
| 249 | 249 | bool *any_writable, bool *any_young, bool *any_dirty) |
| 250 | 250 | { |
| 251 | − unsigned long folio_end_pfn = folio_pfn(folio) + folio_nr_pages(folio); | |
| 252 | − const pte_t *end_ptep = start_ptep + max_nr; | |
| 253 | 251 | pte_t expected_pte, *ptep; |
| 254 | 252 | bool writable, young, dirty; |
| 255 | − int nr; | |
| 253 | + int nr, cur_nr; | |
| 256 | 254 | |
| 257 | 255 | if (any_writable) |
| 258 | 256 | *any_writable = false; |
| @@ -265,11 +263,15 @@ static inline int folio_pte_batch(struct folio *folio, unsigned long addr, · 6 unmodified lines | ||
| 265 | 263 | VM_WARN_ON_FOLIO(!folio_test_large(folio) || max_nr < 1, folio); |
| 266 | 264 | VM_WARN_ON_FOLIO(page_folio(pfn_to_page(pte_pfn(pte))) != folio, folio); |
| 267 | 265 | |
| 266 | + /* Limit max_nr to the actual remaining PFNs in the folio we could batch. */ | |
| 267 | + max_nr = min_t(unsigned long, max_nr, | |
| 268 | + folio_pfn(folio) + folio_nr_pages(folio) - pte_pfn(pte)); | |
| 269 | + | |
| 268 | 270 | nr = pte_batch_hint(start_ptep, pte); |
| 269 | 271 | expected_pte = __pte_batch_clear_ignored(pte_advance_pfn(pte, nr), flags); |
| 270 | 272 | ptep = start_ptep + nr; |
| 271 | 273 | |
| 272 | − while (ptep < end_ptep) { | |
| 274 | + while (nr < max_nr) { | |
| 273 | 275 | pte = ptep_get(ptep); |
| 274 | 276 | if (any_writable) |
| 275 | 277 | writable = !!pte_write(pte); |
| @@ -282,14 +284,6 @@ static inline int folio_pte_batch(struct folio *folio, unsigned long addr, · 6 unmodified lines | ||
| 282 | 284 | if (!pte_same(pte, expected_pte)) |
| 283 | 285 | break; |
| 284 | 286 | |
| 285 | − /* | |
| 286 | − * Stop immediately once we reached the end of the folio. In | |
| 287 | − * corner cases the next PFN might fall into a different | |
| 288 | − * folio. | |
| 289 | − */ | |
| 290 | − if (pte_pfn(pte) >= folio_end_pfn) | |
| 291 | − break; | |
| 292 | − | |
| 293 | 287 | if (any_writable) |
| 294 | 288 | *any_writable |= writable; |
| 295 | 289 | if (any_young) |
| @@ -297,12 +291,13 @@ static inline int folio_pte_batch(struct folio *folio, unsigned long addr, · 1 unmodified line | ||
| 297 | 291 | if (any_dirty) |
| 298 | 292 | *any_dirty |= dirty; |
| 299 | 293 | |
| 300 | − nr = pte_batch_hint(ptep, pte); | |
| 301 | − expected_pte = pte_advance_pfn(expected_pte, nr); | |
| 302 | − ptep += nr; | |
| 294 | + cur_nr = pte_batch_hint(ptep, pte); | |
| 295 | + expected_pte = pte_advance_pfn(expected_pte, cur_nr); | |
| 296 | + ptep += cur_nr; | |
| 297 | + nr += cur_nr; | |
| 303 | 298 | } |
| 304 | 299 | |
| 305 | − return min(ptep - start_ptep, max_nr); | |
| 300 | + return min(nr, max_nr); | |
| 306 | 301 | } |
| 307 | 302 | |
| 308 | 303 | /** |
| @@ -1272,13 +1272,22 @@ int folio_alloc_swap(struct folio *folio, gfp_t gfp) · 1271 unmodified lines | ||
| 1272 | 1272 | VM_BUG_ON_FOLIO(!folio_test_locked(folio), folio); |
| 1273 | 1273 | VM_BUG_ON_FOLIO(!folio_test_uptodate(folio), folio); |
| 1274 | 1274 | |
| 1275 | − /* | |
| 1276 | − * Should not even be attempting large allocations when huge | |
| 1277 | − * page swap is disabled. Warn and fail the allocation. | |
| 1278 | − */ | |
| 1279 | − if (order && (!IS_ENABLED(CONFIG_THP_SWAP) || size > SWAPFILE_CLUSTER)) { | |
| 1280 | − VM_WARN_ON_ONCE(1); | |
| 1281 | − return -EINVAL; | |
| 1275 | + if (order) { | |
| 1276 | + /* | |
| 1277 | + * Reject large allocation when THP_SWAP is disabled, | |
| 1278 | + * the caller should split the folio and try again. | |
| 1279 | + */ | |
| 1280 | + if (!IS_ENABLED(CONFIG_THP_SWAP)) | |
| 1281 | + return -EAGAIN; | |
| 1282 | + | |
| 1283 | + /* | |
| 1284 | + * Allocation size should never exceed cluster size | |
| 1285 | + * (HPAGE_PMD_SIZE). | |
| 1286 | + */ | |
| 1287 | + if (size > SWAPFILE_CLUSTER) { | |
| 1288 | + VM_WARN_ON_ONCE(1); | |
| 1289 | + return -EINVAL; | |
| 1290 | + } | |
| 1282 | 1291 | } |
| 1283 | 1292 | |
| 1284 | 1293 | local_lock(&percpu_swap_cluster.lock); |
| @@ -1940,7 +1940,7 @@ static inline void setup_vmalloc_vm(struct vm_struct *vm, · 1939 unmodified lines | ||
| 1940 | 1940 | { |
| 1941 | 1941 | vm->flags = flags; |
| 1942 | 1942 | vm->addr = (void *)va->va_start; |
| 1943 | − vm->size = va_size(va); | |
| 1943 | + vm->size = vm->requested_size = va_size(va); | |
| 1944 | 1944 | vm->caller = caller; |
| 1945 | 1945 | va->vm = vm; |
| 1946 | 1946 | } |
| @@ -3133,6 +3133,7 @@ struct vm_struct *__get_vm_area_node(unsigned long size, · 1186 unmodified lines | ||
| 3133 | 3133 | |
| 3134 | 3134 | area->flags = flags; |
| 3135 | 3135 | area->caller = caller; |
| 3136 | + area->requested_size = requested_size; | |
| 3136 | 3137 | |
| 3137 | 3138 | va = alloc_vmap_area(size, align, start, end, node, gfp_mask, 0, area); |
| 3138 | 3139 | if (IS_ERR(va)) { |
| @@ -4063,6 +4064,8 @@ EXPORT_SYMBOL(vzalloc_node_noprof); · 924 unmodified lines | ||
| 4063 | 4064 | */ |
| 4064 | 4065 | void *vrealloc_noprof(const void *p, size_t size, gfp_t flags) |
| 4065 | 4066 | { |
| 4067 | + struct vm_struct *vm = NULL; | |
| 4068 | + size_t alloced_size = 0; | |
| 4066 | 4069 | size_t old_size = 0; |
| 4067 | 4070 | void *n; |
| 4068 | 4071 | |
| @@ -4072,15 +4075,17 @@ void *vrealloc_noprof(const void *p, size_t size, gfp_t flags) · 3 unmodified lines | ||
| 4072 | 4075 | } |
| 4073 | 4076 | |
| 4074 | 4077 | if (p) { |
| 4075 | − struct vm_struct *vm; | |
| 4076 | − | |
| 4077 | 4078 | vm = find_vm_area(p); |
| 4078 | 4079 | if (unlikely(!vm)) { |
| 4079 | 4080 | WARN(1, "Trying to vrealloc() nonexistent vm area (%p)\n", p); |
| 4080 | 4081 | return NULL; |
| 4081 | 4082 | } |
| 4082 | 4083 | |
| 4083 | − old_size = get_vm_area_size(vm); | |
| 4084 | + alloced_size = get_vm_area_size(vm); | |
| 4085 | + old_size = vm->requested_size; | |
| 4086 | + if (WARN(alloced_size < old_size, | |
| 4087 | + "vrealloc() has mismatched area vs requested sizes (%p)\n", p)) | |
| 4088 | + return NULL; | |
| 4084 | 4089 | } |
| 4085 | 4090 | |
| 4086 | 4091 | /* |
| @@ -4088,14 +4093,26 @@ void *vrealloc_noprof(const void *p, size_t size, gfp_t flags) · 1 unmodified line | ||
| 4088 | 4093 | * would be a good heuristic for when to shrink the vm_area? |
| 4089 | 4094 | */ |
| 4090 | 4095 | if (size <= old_size) { |
| 4091 | − /* Zero out spare memory. */ | |
| 4092 | − if (want_init_on_alloc(flags)) | |
| 4096 | + /* Zero out "freed" memory. */ | |
| 4097 | + if (want_init_on_free()) | |
| 4093 | 4098 | memset((void *)p + size, 0, old_size - size); |
| 4099 | + vm->requested_size = size; | |
| 4094 | 4100 | kasan_poison_vmalloc(p + size, old_size - size); |
| 4095 | − kasan_unpoison_vmalloc(p, size, KASAN_VMALLOC_PROT_NORMAL); | |
| 4096 | 4101 | return (void *)p; |
| 4097 | 4102 | } |
| 4098 | 4103 | |
| 4104 | + /* | |
| 4105 | + * We already have the bytes available in the allocation; use them. | |
| 4106 | + */ | |
| 4107 | + if (size <= alloced_size) { | |
| 4108 | + kasan_unpoison_vmalloc(p + old_size, size - old_size, | |
| 4109 | + KASAN_VMALLOC_PROT_NORMAL); | |
| 4110 | + /* Zero out "alloced" memory. */ | |
| 4111 | + if (want_init_on_alloc(flags)) | |
| 4112 | + memset((void *)p + old_size, 0, size - old_size); | |
| 4113 | + vm->requested_size = size; | |
| 4114 | + } | |
| 4115 | + | |
| 4099 | 4116 | /* TODO: Grow the vm_area, i.e. allocate and map additional pages. */ |
| 4100 | 4117 | n = __vmalloc_noprof(size, flags); |
| 4101 | 4118 | if (!n) |
| @@ -90,6 +90,8 @@ int check_compaction(unsigned long mem_free, unsigned long hugepage_size, · 89 unmodified lines | ||
| 90 | 90 | int compaction_index = 0; |
| 91 | 91 | char nr_hugepages[20] = {0}; |
| 92 | 92 | char init_nr_hugepages[24] = {0}; |
| 93 | + char target_nr_hugepages[24] = {0}; | |
| 94 | + int slen; | |
| 93 | 95 | |
| 94 | 96 | snprintf(init_nr_hugepages, sizeof(init_nr_hugepages), |
| 95 | 97 | "%lu", initial_nr_hugepages); |
| @@ -106,11 +108,18 @@ int check_compaction(unsigned long mem_free, unsigned long hugepage_size, · 10 unmodified lines | ||
| 106 | 108 | goto out; |
| 107 | 109 | } |
| 108 | 110 | |
| 109 | − /* Request a large number of huge pages. The Kernel will allocate | |
| 110 | − as much as it can */ | |
| 111 | − if (write(fd, "100000", (6*sizeof(char))) != (6*sizeof(char))) { | |
| 112 | − ksft_print_msg("Failed to write 100000 to /proc/sys/vm/nr_hugepages: %s\n", | |
| 113 | − strerror(errno)); | |
| 111 | + /* | |
| 112 | + * Request huge pages for about half of the free memory. The Kernel | |
| 113 | + * will allocate as much as it can, and we expect it will get at least 1/3 | |
| 114 | + */ | |
| 115 | + nr_hugepages_ul = mem_free / hugepage_size / 2; | |
| 116 | + snprintf(target_nr_hugepages, sizeof(target_nr_hugepages), | |
| 117 | + "%lu", nr_hugepages_ul); | |
| 118 | + | |
| 119 | + slen = strlen(target_nr_hugepages); | |
| 120 | + if (write(fd, target_nr_hugepages, slen) != slen) { | |
| 121 | + ksft_print_msg("Failed to write %lu to /proc/sys/vm/nr_hugepages: %s\n", | |
| 122 | + nr_hugepages_ul, strerror(errno)); | |
| 114 | 123 | goto close_fd; |
| 115 | 124 | } |
| 116 | 125 | |
| @@ -271,12 +271,16 @@ FIXTURE_SETUP(guard_regions) · 270 unmodified lines | ||
| 271 | 271 | self->page_size = (unsigned long)sysconf(_SC_PAGESIZE); |
| 272 | 272 | setup_sighandler(); |
| 273 | 273 | |
| 274 | − if (variant->backing == ANON_BACKED) | |
| 274 | + switch (variant->backing) { | |
| 275 | + case ANON_BACKED: | |
| 275 | 276 | return; |
| 276 | − | |
| 277 | − self->fd = open_file( | |
| 278 | − variant->backing == SHMEM_BACKED ? "/tmp/" : "", | |
| 279 | − self->path); | |
| 277 | + case LOCAL_FILE_BACKED: | |
| 278 | + self->fd = open_file("", self->path); | |
| 279 | + break; | |
| 280 | + case SHMEM_BACKED: | |
| 281 | + self->fd = memfd_create(self->path, 0); | |
| 282 | + break; | |
| 283 | + } | |
| 280 | 284 | |
| 281 | 285 | /* We truncate file to at least 100 pages, tests can modify as needed. */ |
| 282 | 286 | ASSERT_EQ(ftruncate(self->fd, 100 * self->page_size), 0); |
| @@ -1696,7 +1700,7 @@ TEST_F(guard_regions, readonly_file) · 1413 unmodified lines | ||
| 1696 | 1700 | char *ptr; |
| 1697 | 1701 | int i; |
| 1698 | 1702 | |
| 1699 | − if (variant->backing == ANON_BACKED) | |
| 1703 | + if (variant->backing != LOCAL_FILE_BACKED) | |
| 1700 | 1704 | SKIP(return, "Read-only test specific to file-backed"); |
| 1701 | 1705 | |
| 1702 | 1706 | /* Map shared so we can populate with pattern, populate it, unmap. */ |
| @@ -3,6 +3,8 @@ · 2 unmodified lines | ||
| 3 | 3 | #ifndef _PKEYS_POWERPC_H |
| 4 | 4 | #define _PKEYS_POWERPC_H |
| 5 | 5 | |
| 6 | +#include <sys/stat.h> | |
| 7 | + | |
| 6 | 8 | #ifndef SYS_pkey_alloc |
| 7 | 9 | # define SYS_pkey_alloc 384 |
| 8 | 10 | # define SYS_pkey_free 385 |
| @@ -102,8 +104,18 @@ static inline void expect_fault_on_read_execonly_key(void *p1, int pkey) · 93 unmodified lines | ||
| 102 | 104 | return; |
| 103 | 105 | } |
| 104 | 106 | |
| 107 | +#define REPEAT_8(s) s s s s s s s s | |
| 108 | +#define REPEAT_64(s) REPEAT_8(s) REPEAT_8(s) REPEAT_8(s) REPEAT_8(s) \ | |
| 109 | + REPEAT_8(s) REPEAT_8(s) REPEAT_8(s) REPEAT_8(s) | |
| 110 | +#define REPEAT_512(s) REPEAT_64(s) REPEAT_64(s) REPEAT_64(s) REPEAT_64(s) \ | |
| 111 | + REPEAT_64(s) REPEAT_64(s) REPEAT_64(s) REPEAT_64(s) | |
| 112 | +#define REPEAT_4096(s) REPEAT_512(s) REPEAT_512(s) REPEAT_512(s) REPEAT_512(s) \ | |
| 113 | + REPEAT_512(s) REPEAT_512(s) REPEAT_512(s) REPEAT_512(s) | |
| 114 | +#define REPEAT_16384(s) REPEAT_4096(s) REPEAT_4096(s) \ | |
| 115 | + REPEAT_4096(s) REPEAT_4096(s) | |
| 116 | + | |
| 105 | 117 | /* 4-byte instructions * 16384 = 64K page */ |
| 106 | −#define __page_o_noops() asm(".rept 16384 ; nop; .endr") | |
| 118 | +#define __page_o_noops() asm(REPEAT_16384("nop\n")) | |
| 107 | 119 | |
| 108 | 120 | static inline void *malloc_pkey_with_mprotect_subpage(long size, int prot, u16 pkey) |
| 109 | 121 | { |
| @@ -1,4 +1,5 @@ | ||
| 1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
| 2 | +#define __SANE_USERSPACE_TYPES__ | |
| 2 | 3 | #include <sys/syscall.h> |
| 3 | 4 | #include <unistd.h> |
| 4 | 5 | |