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 | Luca Weiss <luca@lucaweiss.eu> <luca@z3ntu.xyz> | 447 | Luca Weiss <luca@lucaweiss.eu> <luca@z3ntu.xyz> |
| 448 | Lukasz Luba <lukasz.luba@arm.com> <l.luba@partner.samsung.com> | 448 | Lukasz Luba <lukasz.luba@arm.com> <l.luba@partner.samsung.com> |
| 449 | Luo Jie <quic_luoj@quicinc.com> <luoj@codeaurora.org> | 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 | Maciej W. Rozycki <macro@mips.com> <macro@imgtec.com> | 452 | Maciej W. Rozycki <macro@mips.com> <macro@imgtec.com> |
| 451 | Maciej W. Rozycki <macro@orcam.me.uk> <macro@linux-mips.org> | 453 | Maciej W. Rozycki <macro@orcam.me.uk> <macro@linux-mips.org> |
| 452 | Maharaja Kennadyrajan <quic_mkenna@quicinc.com> <mkenna@codeaurora.org> | 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 | Tycho Andersen <tycho@tycho.pizza> <tycho@tycho.ws> | 751 | Tycho Andersen <tycho@tycho.pizza> <tycho@tycho.ws> |
| 750 | Tzung-Bi Shih <tzungbi@kernel.org> <tzungbi@google.com> | 752 | Tzung-Bi Shih <tzungbi@kernel.org> <tzungbi@google.com> |
| 751 | Uwe Kleine-König <ukleinek@informatik.uni-freiburg.de> | 753 | Uwe Kleine-König <ukleinek@informatik.uni-freiburg.de> |
| 754 | Uwe Kleine-König <u.kleine-koenig@baylibre.com> <ukleinek@baylibre.com> | ||
| 752 | Uwe Kleine-König <u.kleine-koenig@pengutronix.de> | 755 | Uwe Kleine-König <u.kleine-koenig@pengutronix.de> |
| 753 | Uwe Kleine-König <ukleinek@strlen.de> | 756 | Uwe Kleine-König <ukleinek@strlen.de> |
| 754 | Uwe Kleine-König <ukl@pengutronix.de> | 757 | Uwe Kleine-König <ukl@pengutronix.de> |
| @@ -15495,24 +15495,45 @@ F: Documentation/mm/ · 15494 unmodified lines | |||
| 15495 | F: include/linux/gfp.h | 15495 | F: include/linux/gfp.h |
| 15496 | F: include/linux/gfp_types.h | 15496 | F: include/linux/gfp_types.h |
| 15497 | F: include/linux/memfd.h | 15497 | F: include/linux/memfd.h |
| 15498 | F: include/linux/memory.h | ||
| 15499 | F: include/linux/memory_hotplug.h | 15498 | F: include/linux/memory_hotplug.h |
| 15500 | F: include/linux/memory-tiers.h | 15499 | F: include/linux/memory-tiers.h |
| 15501 | F: include/linux/mempolicy.h | 15500 | F: include/linux/mempolicy.h |
| 15502 | F: include/linux/mempool.h | 15501 | F: include/linux/mempool.h |
| 15503 | F: include/linux/memremap.h | 15502 | F: include/linux/memremap.h |
| 15504 | F: include/linux/mm.h | ||
| 15505 | F: include/linux/mm_*.h | ||
| 15506 | F: include/linux/mmzone.h | 15503 | F: include/linux/mmzone.h |
| 15507 | F: include/linux/mmu_notifier.h | 15504 | F: include/linux/mmu_notifier.h |
| 15508 | F: include/linux/pagewalk.h | 15505 | F: include/linux/pagewalk.h |
| 15509 | F: include/linux/rmap.h | ||
| 15510 | F: include/trace/events/ksm.h | 15506 | F: include/trace/events/ksm.h |
| 15511 | F: mm/ | 15507 | F: mm/ |
| 15512 | F: tools/mm/ | 15508 | F: tools/mm/ |
| 15513 | F: tools/testing/selftests/mm/ | 15509 | F: tools/testing/selftests/mm/ |
| 15514 | N: include/linux/page[-_]* | 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 | MEMORY MANAGEMENT - EXECMEM | 15537 | MEMORY MANAGEMENT - EXECMEM |
| 15517 | M: Andrew Morton <akpm@linux-foundation.org> | 15538 | M: Andrew Morton <akpm@linux-foundation.org> |
| 15518 | M: Mike Rapoport <rppt@kernel.org> | 15539 | M: Mike Rapoport <rppt@kernel.org> |
| @@ -15546,6 +15567,19 @@ F: mm/page_alloc.c · 27 unmodified lines | |||
| 15546 | F: include/linux/gfp.h | 15567 | F: include/linux/gfp.h |
| 15547 | F: include/linux/compaction.h | 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 | MEMORY MANAGEMENT - SECRETMEM | 15583 | MEMORY MANAGEMENT - SECRETMEM |
| 15550 | M: Andrew Morton <akpm@linux-foundation.org> | 15584 | M: Andrew Morton <akpm@linux-foundation.org> |
| 15551 | M: Mike Rapoport <rppt@kernel.org> | 15585 | M: Mike Rapoport <rppt@kernel.org> |
| @@ -15554,6 +15588,30 @@ S: Maintained · 2 unmodified lines | |||
| 15554 | F: include/linux/secretmem.h | 15588 | F: include/linux/secretmem.h |
| 15555 | F: mm/secretmem.c | 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 | MEMORY MANAGEMENT - USERFAULTFD | 15615 | MEMORY MANAGEMENT - USERFAULTFD |
| 15558 | M: Andrew Morton <akpm@linux-foundation.org> | 15616 | M: Andrew Morton <akpm@linux-foundation.org> |
| 15559 | R: Peter Xu <peterx@redhat.com> | 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 | . = ASSERT((_end - LOAD_OFFSET <= KERNEL_IMAGE_SIZE), | 478 | . = ASSERT((_end - LOAD_OFFSET <= KERNEL_IMAGE_SIZE), |
| 472 | "kernel image bigger than KERNEL_IMAGE_SIZE"); | 479 | "kernel image bigger than KERNEL_IMAGE_SIZE"); |
| 480 | #endif | ||
| 473 | 481 | ||
| 474 | /* needed for Clang - see arch/x86/entry/entry.S */ | 482 | /* needed for Clang - see arch/x86/entry/entry.S */ |
| 475 | PROVIDE(__ref_stack_chk_guard = __stack_chk_guard); | 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 | int blocksize; | 705 | int blocksize; |
| 706 | int err; | 706 | int err; |
| 707 | 707 | ||
| 708 | down_write(&nilfs->ns_sem); | ||
| 709 | |||
| 710 | blocksize = sb_min_blocksize(sb, NILFS_MIN_BLOCK_SIZE); | 708 | blocksize = sb_min_blocksize(sb, NILFS_MIN_BLOCK_SIZE); |
| 711 | if (!blocksize) { | 709 | if (!blocksize) { |
| 712 | nilfs_err(sb, "unable to set blocksize"); | 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 | set_nilfs_init(nilfs); | 777 | set_nilfs_init(nilfs); |
| 780 | err = 0; | 778 | err = 0; |
| 781 | out: | 779 | out: |
| 782 | up_write(&nilfs->ns_sem); | ||
| 783 | return err; | 780 | return err; |
| 784 | 781 | ||
| 785 | failed_sbh: | 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 | if (IS_ERR(folios[numfolios])) { | 6918 | if (IS_ERR(folios[numfolios])) { |
| 6919 | ret = PTR_ERR(folios[numfolios]); | 6919 | ret = PTR_ERR(folios[numfolios]); |
| 6920 | mlog_errno(ret); | 6920 | mlog_errno(ret); |
| 6921 | folios[numfolios] = NULL; | ||
| 6921 | goto out; | 6922 | goto out; |
| 6922 | } | 6923 | } |
| 6923 | 6924 | ||
| @@ -174,7 +174,7 @@ int ocfs2_recovery_init(struct ocfs2_super *osb) · 173 unmodified lines | |||
| 174 | struct ocfs2_recovery_map *rm; | 174 | struct ocfs2_recovery_map *rm; |
| 175 | 175 | ||
| 176 | mutex_init(&osb->recovery_lock); | 176 | mutex_init(&osb->recovery_lock); |
| 177 | osb->disable_recovery = 0; | 177 | osb->recovery_state = OCFS2_REC_ENABLED; |
| 178 | osb->recovery_thread_task = NULL; | 178 | osb->recovery_thread_task = NULL; |
| 179 | init_waitqueue_head(&osb->recovery_event); | 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 | return 0; | 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 | static int ocfs2_recovery_thread_running(struct ocfs2_super *osb) | 193 | static int ocfs2_recovery_thread_running(struct ocfs2_super *osb) |
| 197 | { | 194 | { |
| 198 | mb(); | ||
| 199 | return osb->recovery_thread_task != NULL; | 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 | mutex_lock(&osb->recovery_lock); | 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 | mutex_unlock(&osb->recovery_lock); | 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 | 220 | /* |
| 214 | * launched, so wait for any recovery completion work to | 221 | * At this point we know that no more recovery work can be queued so |
| 215 | * complete. */ | 222 | * wait for any recovery completion work to complete. |
| 223 | */ | ||
| 216 | if (osb->ocfs2_wq) | 224 | if (osb->ocfs2_wq) |
| 217 | flush_workqueue(osb->ocfs2_wq); | 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 | * Now that recovery is shut down, and the osb is about to be | 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 | restart: | 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 | status = ocfs2_super_lock(osb, 1); | 1509 | status = ocfs2_super_lock(osb, 1); |
| 1476 | if (status < 0) { | 1510 | if (status < 0) { |
| 1477 | mlog_errno(status); | 1511 | mlog_errno(status); |
| @@ -1569,27 +1603,29 @@ bail: · 91 unmodified lines | |||
| 1569 | 1603 | ||
| 1570 | ocfs2_free_replay_slots(osb); | 1604 | ocfs2_free_replay_slots(osb); |
| 1571 | osb->recovery_thread_task = NULL; | 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 | wake_up(&osb->recovery_event); | 1608 | wake_up(&osb->recovery_event); |
| 1574 | 1609 | ||
| 1575 | mutex_unlock(&osb->recovery_lock); | 1610 | mutex_unlock(&osb->recovery_lock); |
| 1576 | 1611 | ||
| 1577 | if (quota_enabled) | 1612 | kfree(rm_quota); |
| 1578 | kfree(rm_quota); | ||
| 1579 | 1613 | ||
| 1580 | return status; | 1614 | return status; |
| 1581 | } | 1615 | } |
| 1582 | 1616 | ||
| 1583 | void ocfs2_recovery_thread(struct ocfs2_super *osb, int node_num) | 1617 | void ocfs2_recovery_thread(struct ocfs2_super *osb, int node_num) |
| 1584 | { | 1618 | { |
| 1619 | int was_set = -1; | ||
| 1620 | |||
| 1585 | mutex_lock(&osb->recovery_lock); | 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 | trace_ocfs2_recovery_thread(node_num, osb->node_num, | 1625 | trace_ocfs2_recovery_thread(node_num, osb->node_num, |
| 1588 | osb->disable_recovery, osb->recovery_thread_task, | 1626 | osb->recovery_state, osb->recovery_thread_task, was_set); |
| 1589 | osb->disable_recovery ? | ||
| 1590 | -1 : ocfs2_recovery_map_set(osb, node_num)); | ||
| 1591 | 1627 | ||
| 1592 | if (osb->disable_recovery) | 1628 | if (osb->recovery_state >= OCFS2_REC_WANT_DISABLE) |
| 1593 | goto out; | 1629 | goto out; |
| 1594 | 1630 | ||
| 1595 | if (osb->recovery_thread_task) | 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 | int ocfs2_recovery_init(struct ocfs2_super *osb); | 149 | int ocfs2_recovery_init(struct ocfs2_super *osb); |
| 150 | void ocfs2_recovery_exit(struct ocfs2_super *osb); | 150 | void ocfs2_recovery_exit(struct ocfs2_super *osb); |
| 151 | void ocfs2_recovery_disable_quota(struct ocfs2_super *osb); | ||
| 151 | 152 | ||
| 152 | int ocfs2_compute_replay_slots(struct ocfs2_super *osb); | 153 | int ocfs2_compute_replay_slots(struct ocfs2_super *osb); |
| 153 | void ocfs2_free_replay_slots(struct ocfs2_super *osb); | 154 | void ocfs2_free_replay_slots(struct ocfs2_super *osb); |
| @@ -308,6 +308,21 @@ enum ocfs2_journal_trigger_type { · 307 unmodified lines | |||
| 308 | void ocfs2_initialize_journal_triggers(struct super_block *sb, | 308 | void ocfs2_initialize_journal_triggers(struct super_block *sb, |
| 309 | struct ocfs2_triggers triggers[]); | 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 | struct ocfs2_journal; | 326 | struct ocfs2_journal; |
| 312 | struct ocfs2_slot_info; | 327 | struct ocfs2_slot_info; |
| 313 | struct ocfs2_recovery_map; | 328 | struct ocfs2_recovery_map; |
| @@ -370,7 +385,7 @@ struct ocfs2_super · 56 unmodified lines | |||
| 370 | struct ocfs2_recovery_map *recovery_map; | 385 | struct ocfs2_recovery_map *recovery_map; |
| 371 | struct ocfs2_replay_map *replay_map; | 386 | struct ocfs2_replay_map *replay_map; |
| 372 | struct task_struct *recovery_thread_task; | 387 | struct task_struct *recovery_thread_task; |
| 373 | int disable_recovery; | 388 | enum ocfs2_recovery_state recovery_state; |
| 374 | wait_queue_head_t checkpoint_event; | 389 | wait_queue_head_t checkpoint_event; |
| 375 | struct ocfs2_journal *journal; | 390 | struct ocfs2_journal *journal; |
| 376 | unsigned long osb_commit_interval; | 391 | unsigned long osb_commit_interval; |
| @@ -453,8 +453,7 @@ out: · 452 unmodified lines | |||
| 453 | 453 | ||
| 454 | /* Sync changes in local quota file into global quota file and | 454 | /* Sync changes in local quota file into global quota file and |
| 455 | * reinitialize local quota file. | 455 | * reinitialize local quota file. |
| 456 | * The function expects local quota file to be already locked and | 456 | * The function expects local quota file to be already locked. */ |
| 457 | * s_umount locked in shared mode. */ | ||
| 458 | static int ocfs2_recover_local_quota_file(struct inode *lqinode, | 457 | static int ocfs2_recover_local_quota_file(struct inode *lqinode, |
| 459 | int type, | 458 | int type, |
| 460 | struct ocfs2_quota_recovery *rec) | 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 | unsigned int ino[OCFS2_MAXQUOTAS] = { LOCAL_USER_QUOTA_SYSTEM_INODE, | 588 | unsigned int ino[OCFS2_MAXQUOTAS] = { LOCAL_USER_QUOTA_SYSTEM_INODE, |
| 590 | LOCAL_GROUP_QUOTA_SYSTEM_INODE }; | 589 | LOCAL_GROUP_QUOTA_SYSTEM_INODE }; |
| 591 | struct super_block *sb = osb->sb; | ||
| 592 | struct ocfs2_local_disk_dqinfo *ldinfo; | 590 | struct ocfs2_local_disk_dqinfo *ldinfo; |
| 593 | struct buffer_head *bh; | 591 | struct buffer_head *bh; |
| 594 | handle_t *handle; | 592 | handle_t *handle; |
| @@ -600,7 +598,6 @@ int ocfs2_finish_quota_recovery(struct ocfs2_super *osb, · 5 unmodified lines | |||
| 600 | printk(KERN_NOTICE "ocfs2: Finishing quota recovery on device (%s) for " | 598 | printk(KERN_NOTICE "ocfs2: Finishing quota recovery on device (%s) for " |
| 601 | "slot %u\n", osb->dev_str, slot_num); | 599 | "slot %u\n", osb->dev_str, slot_num); |
| 602 | 600 | ||
| 603 | down_read(&sb->s_umount); | ||
| 604 | for (type = 0; type < OCFS2_MAXQUOTAS; type++) { | 601 | for (type = 0; type < OCFS2_MAXQUOTAS; type++) { |
| 605 | if (list_empty(&(rec->r_list[type]))) | 602 | if (list_empty(&(rec->r_list[type]))) |
| 606 | continue; | 603 | continue; |
| @@ -677,7 +674,6 @@ out_put: · 70 unmodified lines | |||
| 677 | break; | 674 | break; |
| 678 | } | 675 | } |
| 679 | out: | 676 | out: |
| 680 | up_read(&sb->s_umount); | ||
| 681 | kfree(rec); | 677 | kfree(rec); |
| 682 | return status; | 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 | ocfs2_release_local_quota_bitmaps(&oinfo->dqi_chunk); | 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 | 842 | * ocfs2_dismount_volume() has already aborted quota recovery... |
| 847 | * recovery thread... | ||
| 848 | */ | 843 | */ |
| 849 | if (oinfo->dqi_rec) { | 844 | if (oinfo->dqi_rec) { |
| 850 | ocfs2_free_quota_recovery(oinfo->dqi_rec); | 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 | bg_bh = ocfs2_block_group_alloc_contig(osb, handle, alloc_inode, | 699 | bg_bh = ocfs2_block_group_alloc_contig(osb, handle, alloc_inode, |
| 700 | ac, cl); | 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 | bg_bh = ocfs2_block_group_alloc_discontig(handle, | 703 | bg_bh = ocfs2_block_group_alloc_discontig(handle, |
| 703 | alloc_inode, | 704 | alloc_inode, |
| 704 | ac, cl); | 705 | ac, cl); |
| 706 | } | ||
| 705 | if (IS_ERR(bg_bh)) { | 707 | if (IS_ERR(bg_bh)) { |
| 706 | status = PTR_ERR(bg_bh); | 708 | status = PTR_ERR(bg_bh); |
| 707 | bg_bh = NULL; | 709 | bg_bh = NULL; |
| @@ -1794,6 +1796,7 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac, · 1086 unmodified lines | |||
| 1794 | { | 1796 | { |
| 1795 | int status; | 1797 | int status; |
| 1796 | u16 chain; | 1798 | u16 chain; |
| 1799 | u32 contig_bits; | ||
| 1797 | u64 next_group; | 1800 | u64 next_group; |
| 1798 | struct inode *alloc_inode = ac->ac_inode; | 1801 | struct inode *alloc_inode = ac->ac_inode; |
| 1799 | struct buffer_head *group_bh = NULL; | 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 | status = -ENOSPC; | 1822 | status = -ENOSPC; |
| 1820 | /* for now, the chain search is a bit simplistic. We just use | 1823 | /* for now, the chain search is a bit simplistic. We just use |
| 1821 | * the 1st group with any empty bits. */ | 1824 | * the 1st group with any empty bits. */ |
| 1822 | while ((status = ac->ac_group_search(alloc_inode, group_bh, | 1825 | while (1) { |
| 1823 | bits_wanted, min_bits, | 1826 | if (ac->ac_which == OCFS2_AC_USE_MAIN_DISCONTIG) { |
| 1824 | ac->ac_max_block, | 1827 | contig_bits = le16_to_cpu(bg->bg_contig_free_bits); |
| 1825 | res)) == -ENOSPC) { | 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 | if (!bg->bg_next_group) | 1840 | if (!bg->bg_next_group) |
| 1827 | break; | 1841 | break; |
| 1828 | 1842 | ||
| @@ -1982,6 +1996,7 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac, · 153 unmodified lines | |||
| 1982 | victim = ocfs2_find_victim_chain(cl); | 1996 | victim = ocfs2_find_victim_chain(cl); |
| 1983 | ac->ac_chain = victim; | 1997 | ac->ac_chain = victim; |
| 1984 | 1998 | ||
| 1999 | search: | ||
| 1985 | status = ocfs2_search_chain(ac, handle, bits_wanted, min_bits, | 2000 | status = ocfs2_search_chain(ac, handle, bits_wanted, min_bits, |
| 1986 | res, &bits_left); | 2001 | res, &bits_left); |
| 1987 | if (!status) { | 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 | set_hint: | 2050 | set_hint: |
| 2026 | if (status != -ENOSPC) { | 2051 | if (status != -ENOSPC) { |
| 2027 | /* If the next search of this group is not likely to | 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 | BUG_ON(ac->ac_bits_given >= ac->ac_bits_wanted); | 2390 | BUG_ON(ac->ac_bits_given >= ac->ac_bits_wanted); |
| 2366 | 2391 | ||
| 2367 | BUG_ON(ac->ac_which != OCFS2_AC_USE_LOCAL | 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 | if (ac->ac_which == OCFS2_AC_USE_LOCAL) { | 2396 | if (ac->ac_which == OCFS2_AC_USE_LOCAL) { |
| 2371 | WARN_ON(min_clusters > 1); | 2397 | WARN_ON(min_clusters > 1); |
| @@ -29,6 +29,7 @@ struct ocfs2_alloc_context { · 28 unmodified lines | |||
| 29 | #define OCFS2_AC_USE_MAIN 2 | 29 | #define OCFS2_AC_USE_MAIN 2 |
| 30 | #define OCFS2_AC_USE_INODE 3 | 30 | #define OCFS2_AC_USE_INODE 3 |
| 31 | #define OCFS2_AC_USE_META 4 | 31 | #define OCFS2_AC_USE_META 4 |
| 32 | #define OCFS2_AC_USE_MAIN_DISCONTIG 5 | ||
| 32 | u32 ac_which; | 33 | u32 ac_which; |
| 33 | 34 | ||
| 34 | /* these are used by the chain search */ | 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 | /* Orphan scan should be stopped as early as possible */ | 1812 | /* Orphan scan should be stopped as early as possible */ |
| 1813 | ocfs2_orphan_scan_stop(osb); | 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 | ocfs2_disable_quotas(osb); | 1818 | ocfs2_disable_quotas(osb); |
| 1816 | 1819 | ||
| 1817 | /* All dquots should be freed by now */ | 1820 | /* All dquots should be freed by now */ |
| @@ -1585,8 +1585,11 @@ static int userfaultfd_copy(struct userfaultfd_ctx *ctx, · 1584 unmodified lines | |||
| 1585 | user_uffdio_copy = (struct uffdio_copy __user *) arg; | 1585 | user_uffdio_copy = (struct uffdio_copy __user *) arg; |
| 1586 | 1586 | ||
| 1587 | ret = -EAGAIN; | 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 | goto out; | 1591 | goto out; |
| 1592 | } | ||
| 1590 | 1593 | ||
| 1591 | ret = -EFAULT; | 1594 | ret = -EFAULT; |
| 1592 | if (copy_from_user(&uffdio_copy, user_uffdio_copy, | 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 | user_uffdio_zeropage = (struct uffdio_zeropage __user *) arg; | 1644 | user_uffdio_zeropage = (struct uffdio_zeropage __user *) arg; |
| 1642 | 1645 | ||
| 1643 | ret = -EAGAIN; | 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 | goto out; | 1650 | goto out; |
| 1651 | } | ||
| 1646 | 1652 | ||
| 1647 | ret = -EFAULT; | 1653 | ret = -EFAULT; |
| 1648 | if (copy_from_user(&uffdio_zeropage, user_uffdio_zeropage, | 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 | user_uffdio_continue = (struct uffdio_continue __user *)arg; | 1750 | user_uffdio_continue = (struct uffdio_continue __user *)arg; |
| 1745 | 1751 | ||
| 1746 | ret = -EAGAIN; | 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 | goto out; | 1756 | goto out; |
| 1757 | } | ||
| 1749 | 1758 | ||
| 1750 | ret = -EFAULT; | 1759 | ret = -EFAULT; |
| 1751 | if (copy_from_user(&uffdio_continue, user_uffdio_continue, | 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 | user_uffdio_poison = (struct uffdio_poison __user *)arg; | 1810 | user_uffdio_poison = (struct uffdio_poison __user *)arg; |
| 1802 | 1811 | ||
| 1803 | ret = -EAGAIN; | 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 | goto out; | 1816 | goto out; |
| 1817 | } | ||
| 1806 | 1818 | ||
| 1807 | ret = -EFAULT; | 1819 | ret = -EFAULT; |
| 1808 | if (copy_from_user(&uffdio_poison, user_uffdio_poison, | 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 | user_uffdio_move = (struct uffdio_move __user *) arg; | 1883 | user_uffdio_move = (struct uffdio_move __user *) arg; |
| 1872 | 1884 | ||
| 1873 | if (atomic_read(&ctx->mmap_changing)) | 1885 | ret = -EAGAIN; |
| 1874 | return -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 | if (copy_from_user(&uffdio_move, user_uffdio_move, | 1892 | if (copy_from_user(&uffdio_move, user_uffdio_move, |
| 1877 | /* don't copy "move" last field */ | 1893 | /* don't copy "move" last field */ |
| @@ -61,6 +61,7 @@ struct vm_struct { · 60 unmodified lines | |||
| 61 | unsigned int nr_pages; | 61 | unsigned int nr_pages; |
| 62 | phys_addr_t phys_addr; | 62 | phys_addr_t phys_addr; |
| 63 | const void *caller; | 63 | const void *caller; |
| 64 | unsigned long requested_size; | ||
| 64 | }; | 65 | }; |
| 65 | 66 | ||
| 66 | struct vmap_area { | 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 | void split_huge_pmd_locked(struct vm_area_struct *vma, unsigned long address, | 3075 | void split_huge_pmd_locked(struct vm_area_struct *vma, unsigned long address, |
| 3076 | pmd_t *pmd, bool freeze, struct folio *folio) | 3076 | pmd_t *pmd, bool freeze, struct folio *folio) |
| 3077 | { | 3077 | { |
| 3078 | bool pmd_migration = is_pmd_migration_entry(*pmd); | ||
| 3079 | |||
| 3078 | VM_WARN_ON_ONCE(folio && !folio_test_pmd_mappable(folio)); | 3080 | VM_WARN_ON_ONCE(folio && !folio_test_pmd_mappable(folio)); |
| 3079 | VM_WARN_ON_ONCE(!IS_ALIGNED(address, HPAGE_PMD_SIZE)); | 3081 | VM_WARN_ON_ONCE(!IS_ALIGNED(address, HPAGE_PMD_SIZE)); |
| 3080 | VM_WARN_ON_ONCE(folio && !folio_test_locked(folio)); | 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 | * require a folio to check the PMD against. Otherwise, there | 3087 | * require a folio to check the PMD against. Otherwise, there |
| 3086 | * is a risk of replacing the wrong folio. | 3088 | * is a risk of replacing the wrong folio. |
| 3087 | */ | 3089 | */ |
| 3088 | if (pmd_trans_huge(*pmd) || pmd_devmap(*pmd) || | 3090 | if (pmd_trans_huge(*pmd) || pmd_devmap(*pmd) || pmd_migration) { |
| 3089 | is_pmd_migration_entry(*pmd)) { | 3091 | /* |
| 3090 | if (folio && folio != pmd_folio(*pmd)) | 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 | return; | 3096 | return; |
| 3092 | __split_huge_pmd_locked(vma, pmd, address, freeze); | 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 | list_for_each_entry_safe(folio, next, src_list, lru) { | 4035 | list_for_each_entry_safe(folio, next, src_list, lru) { |
| 4036 | int i; | 4036 | int i; |
| 4037 | bool cma; | ||
| 4037 | 4038 | ||
| 4038 | if (folio_test_hugetlb_vmemmap_optimized(folio)) | 4039 | if (folio_test_hugetlb_vmemmap_optimized(folio)) |
| 4039 | continue; | 4040 | continue; |
| 4040 | 4041 | ||
| 4042 | cma = folio_test_hugetlb_cma(folio); | ||
| 4043 | |||
| 4041 | list_del(&folio->lru); | 4044 | list_del(&folio->lru); |
| 4042 | 4045 | ||
| 4043 | split_page_owner(&folio->page, huge_page_order(src), huge_page_order(dst)); | 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 | new_folio->mapping = NULL; | 4057 | new_folio->mapping = NULL; |
| 4055 | init_new_hugetlb_folio(dst, new_folio); | 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 | list_add(&new_folio->lru, &dst_list); | 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 | pte_t *start_ptep, pte_t pte, int max_nr, fpb_t flags, | 248 | pte_t *start_ptep, pte_t pte, int max_nr, fpb_t flags, |
| 249 | bool *any_writable, bool *any_young, bool *any_dirty) | 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 | pte_t expected_pte, *ptep; | 251 | pte_t expected_pte, *ptep; |
| 254 | bool writable, young, dirty; | 252 | bool writable, young, dirty; |
| 255 | int nr; | 253 | int nr, cur_nr; |
| 256 | 254 | ||
| 257 | if (any_writable) | 255 | if (any_writable) |
| 258 | *any_writable = false; | 256 | *any_writable = false; |
| @@ -265,11 +263,15 @@ static inline int folio_pte_batch(struct folio *folio, unsigned long addr, · 6 unmodified lines | |||
| 265 | VM_WARN_ON_FOLIO(!folio_test_large(folio) || max_nr < 1, folio); | 263 | VM_WARN_ON_FOLIO(!folio_test_large(folio) || max_nr < 1, folio); |
| 266 | VM_WARN_ON_FOLIO(page_folio(pfn_to_page(pte_pfn(pte))) != folio, folio); | 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 | nr = pte_batch_hint(start_ptep, pte); | 270 | nr = pte_batch_hint(start_ptep, pte); |
| 269 | expected_pte = __pte_batch_clear_ignored(pte_advance_pfn(pte, nr), flags); | 271 | expected_pte = __pte_batch_clear_ignored(pte_advance_pfn(pte, nr), flags); |
| 270 | ptep = start_ptep + nr; | 272 | ptep = start_ptep + nr; |
| 271 | 273 | ||
| 272 | while (ptep < end_ptep) { | 274 | while (nr < max_nr) { |
| 273 | pte = ptep_get(ptep); | 275 | pte = ptep_get(ptep); |
| 274 | if (any_writable) | 276 | if (any_writable) |
| 275 | writable = !!pte_write(pte); | 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 | if (!pte_same(pte, expected_pte)) | 284 | if (!pte_same(pte, expected_pte)) |
| 283 | break; | 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 | if (any_writable) | 287 | if (any_writable) |
| 294 | *any_writable |= writable; | 288 | *any_writable |= writable; |
| 295 | if (any_young) | 289 | if (any_young) |
| @@ -297,12 +291,13 @@ static inline int folio_pte_batch(struct folio *folio, unsigned long addr, · 1 unmodified line | |||
| 297 | if (any_dirty) | 291 | if (any_dirty) |
| 298 | *any_dirty |= dirty; | 292 | *any_dirty |= dirty; |
| 299 | 293 | ||
| 300 | nr = pte_batch_hint(ptep, pte); | 294 | cur_nr = pte_batch_hint(ptep, pte); |
| 301 | expected_pte = pte_advance_pfn(expected_pte, nr); | 295 | expected_pte = pte_advance_pfn(expected_pte, cur_nr); |
| 302 | ptep += 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 | VM_BUG_ON_FOLIO(!folio_test_locked(folio), folio); | 1272 | VM_BUG_ON_FOLIO(!folio_test_locked(folio), folio); |
| 1273 | VM_BUG_ON_FOLIO(!folio_test_uptodate(folio), folio); | 1273 | VM_BUG_ON_FOLIO(!folio_test_uptodate(folio), folio); |
| 1274 | 1274 | ||
| 1275 | /* | 1275 | if (order) { |
| 1276 | * Should not even be attempting large allocations when huge | 1276 | /* |
| 1277 | * page swap is disabled. Warn and fail the allocation. | 1277 | * Reject large allocation when THP_SWAP is disabled, |
| 1278 | */ | 1278 | * the caller should split the folio and try again. |
| 1279 | if (order && (!IS_ENABLED(CONFIG_THP_SWAP) || size > SWAPFILE_CLUSTER)) { | 1279 | */ |
| 1280 | VM_WARN_ON_ONCE(1); | 1280 | if (!IS_ENABLED(CONFIG_THP_SWAP)) |
| 1281 | return -EINVAL; | 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 | local_lock(&percpu_swap_cluster.lock); | 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 | vm->flags = flags; | 1941 | vm->flags = flags; |
| 1942 | vm->addr = (void *)va->va_start; | 1942 | vm->addr = (void *)va->va_start; |
| 1943 | vm->size = va_size(va); | 1943 | vm->size = vm->requested_size = va_size(va); |
| 1944 | vm->caller = caller; | 1944 | vm->caller = caller; |
| 1945 | va->vm = vm; | 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 | area->flags = flags; | 3134 | area->flags = flags; |
| 3135 | area->caller = caller; | 3135 | area->caller = caller; |
| 3136 | area->requested_size = requested_size; | ||
| 3136 | 3137 | ||
| 3137 | va = alloc_vmap_area(size, align, start, end, node, gfp_mask, 0, area); | 3138 | va = alloc_vmap_area(size, align, start, end, node, gfp_mask, 0, area); |
| 3138 | if (IS_ERR(va)) { | 3139 | if (IS_ERR(va)) { |
| @@ -4063,6 +4064,8 @@ EXPORT_SYMBOL(vzalloc_node_noprof); · 924 unmodified lines | |||
| 4063 | */ | 4064 | */ |
| 4064 | void *vrealloc_noprof(const void *p, size_t size, gfp_t flags) | 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 | size_t old_size = 0; | 4069 | size_t old_size = 0; |
| 4067 | void *n; | 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 | if (p) { | 4077 | if (p) { |
| 4075 | struct vm_struct *vm; | ||
| 4076 | |||
| 4077 | vm = find_vm_area(p); | 4078 | vm = find_vm_area(p); |
| 4078 | if (unlikely(!vm)) { | 4079 | if (unlikely(!vm)) { |
| 4079 | WARN(1, "Trying to vrealloc() nonexistent vm area (%p)\n", p); | 4080 | WARN(1, "Trying to vrealloc() nonexistent vm area (%p)\n", p); |
| 4080 | return NULL; | 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 | * would be a good heuristic for when to shrink the vm_area? | 4093 | * would be a good heuristic for when to shrink the vm_area? |
| 4089 | */ | 4094 | */ |
| 4090 | if (size <= old_size) { | 4095 | if (size <= old_size) { |
| 4091 | /* Zero out spare memory. */ | 4096 | /* Zero out "freed" memory. */ |
| 4092 | if (want_init_on_alloc(flags)) | 4097 | if (want_init_on_free()) |
| 4093 | memset((void *)p + size, 0, old_size - size); | 4098 | memset((void *)p + size, 0, old_size - size); |
| 4099 | vm->requested_size = size; | ||
| 4094 | kasan_poison_vmalloc(p + size, old_size - size); | 4100 | kasan_poison_vmalloc(p + size, old_size - size); |
| 4095 | kasan_unpoison_vmalloc(p, size, KASAN_VMALLOC_PROT_NORMAL); | ||
| 4096 | return (void *)p; | 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 | /* TODO: Grow the vm_area, i.e. allocate and map additional pages. */ | 4116 | /* TODO: Grow the vm_area, i.e. allocate and map additional pages. */ |
| 4100 | n = __vmalloc_noprof(size, flags); | 4117 | n = __vmalloc_noprof(size, flags); |
| 4101 | if (!n) | 4118 | if (!n) |
| @@ -90,6 +90,8 @@ int check_compaction(unsigned long mem_free, unsigned long hugepage_size, · 89 unmodified lines | |||
| 90 | int compaction_index = 0; | 90 | int compaction_index = 0; |
| 91 | char nr_hugepages[20] = {0}; | 91 | char nr_hugepages[20] = {0}; |
| 92 | char init_nr_hugepages[24] = {0}; | 92 | char init_nr_hugepages[24] = {0}; |
| 93 | char target_nr_hugepages[24] = {0}; | ||
| 94 | int slen; | ||
| 93 | 95 | ||
| 94 | snprintf(init_nr_hugepages, sizeof(init_nr_hugepages), | 96 | snprintf(init_nr_hugepages, sizeof(init_nr_hugepages), |
| 95 | "%lu", initial_nr_hugepages); | 97 | "%lu", initial_nr_hugepages); |
| @@ -106,11 +108,18 @@ int check_compaction(unsigned long mem_free, unsigned long hugepage_size, · 10 unmodified lines | |||
| 106 | goto out; | 108 | goto out; |
| 107 | } | 109 | } |
| 108 | 110 | ||
| 109 | /* Request a large number of huge pages. The Kernel will allocate | 111 | /* |
| 110 | as much as it can */ | 112 | * Request huge pages for about half of the free memory. The Kernel |
| 111 | if (write(fd, "100000", (6*sizeof(char))) != (6*sizeof(char))) { | 113 | * will allocate as much as it can, and we expect it will get at least 1/3 |
| 112 | ksft_print_msg("Failed to write 100000 to /proc/sys/vm/nr_hugepages: %s\n", | 114 | */ |
| 113 | strerror(errno)); | 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 | goto close_fd; | 123 | goto close_fd; |
| 115 | } | 124 | } |
| 116 | 125 | ||
| @@ -271,12 +271,16 @@ FIXTURE_SETUP(guard_regions) · 270 unmodified lines | |||
| 271 | self->page_size = (unsigned long)sysconf(_SC_PAGESIZE); | 271 | self->page_size = (unsigned long)sysconf(_SC_PAGESIZE); |
| 272 | setup_sighandler(); | 272 | setup_sighandler(); |
| 273 | 273 | ||
| 274 | if (variant->backing == ANON_BACKED) | 274 | switch (variant->backing) { |
| 275 | case ANON_BACKED: | ||
| 275 | return; | 276 | return; |
| 276 | 277 | case LOCAL_FILE_BACKED: | |
| 277 | self->fd = open_file( | 278 | self->fd = open_file("", self->path); |
| 278 | variant->backing == SHMEM_BACKED ? "/tmp/" : "", | 279 | break; |
| 279 | self->path); | 280 | case SHMEM_BACKED: |
| 281 | self->fd = memfd_create(self->path, 0); | ||
| 282 | break; | ||
| 283 | } | ||
| 280 | 284 | ||
| 281 | /* We truncate file to at least 100 pages, tests can modify as needed. */ | 285 | /* We truncate file to at least 100 pages, tests can modify as needed. */ |
| 282 | ASSERT_EQ(ftruncate(self->fd, 100 * self->page_size), 0); | 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 | char *ptr; | 1700 | char *ptr; |
| 1697 | int i; | 1701 | int i; |
| 1698 | 1702 | ||
| 1699 | if (variant->backing == ANON_BACKED) | 1703 | if (variant->backing != LOCAL_FILE_BACKED) |
| 1700 | SKIP(return, "Read-only test specific to file-backed"); | 1704 | SKIP(return, "Read-only test specific to file-backed"); |
| 1701 | 1705 | ||
| 1702 | /* Map shared so we can populate with pattern, populate it, unmap. */ | 1706 | /* Map shared so we can populate with pattern, populate it, unmap. */ |
| @@ -3,6 +3,8 @@ · 2 unmodified lines | |||
| 3 | #ifndef _PKEYS_POWERPC_H | 3 | #ifndef _PKEYS_POWERPC_H |
| 4 | #define _PKEYS_POWERPC_H | 4 | #define _PKEYS_POWERPC_H |
| 5 | 5 | ||
| 6 | #include <sys/stat.h> | ||
| 7 | |||
| 6 | #ifndef SYS_pkey_alloc | 8 | #ifndef SYS_pkey_alloc |
| 7 | # define SYS_pkey_alloc 384 | 9 | # define SYS_pkey_alloc 384 |
| 8 | # define SYS_pkey_free 385 | 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 | return; | 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 | /* 4-byte instructions * 16384 = 64K page */ | 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 | static inline void *malloc_pkey_with_mprotect_subpage(long size, int prot, u16 pkey) | 120 | static inline void *malloc_pkey_with_mprotect_subpage(long size, int prot, u16 pkey) |
| 109 | { | 121 | { |
| @@ -1,4 +1,5 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-only | 1 | // SPDX-License-Identifier: GPL-2.0-only |
| 2 | #define __SANE_USERSPACE_TYPES__ | ||
| 2 | #include <sys/syscall.h> | 3 | #include <sys/syscall.h> |
| 3 | #include <unistd.h> | 4 | #include <unistd.h> |
| 4 | 5 | ||