diff options
| author | Joonwon Kang <joonwonkang@google.com> | 2026-05-13 08:51:14 +0000 |
|---|---|---|
| committer | Andrew Morton <akpm@linux-foundation.org> | 2026-05-28 21:31:59 -0700 |
| commit | e52d5d6727f5c4045fb9c42438ee2886955f3fb9 (patch) | |
| tree | 20c35878dc74fbcfbe8a57edcc30706e13352bd3 /mm | |
| parent | 7a7ef76062e1e82d2a35c650f95a6656d1c38a0c (diff) | |
| download | linux-next-history-e52d5d6727f5c4045fb9c42438ee2886955f3fb9.tar.gz | |
percpu: do not trust hint starts when they are not set
contig_hint_start can be trusted outside the hint update function since it
will be updated everytime contig_hint is broken. On the other hand,
scan_hint_start might still be invalid anywhere in the code due to the
broken scan_hint not being updated promptly. If those starts are trusted
when they are not set, it could lead to false invalidation or update of
the hints.
Link: https://lore.kernel.org/20260513085117.1024175-2-joonwonkang@google.com
Signed-off-by: Joonwon Kang <joonwonkang@google.com>
Reviewed-by: Dennis Zhou <dennis@kernel.org>
Cc: Tejun Heo <tj@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Diffstat (limited to 'mm')
| -rw-r--r-- | mm/percpu.c | 20 |
1 files changed, 13 insertions, 7 deletions
diff --git a/mm/percpu.c b/mm/percpu.c index 7c508cb3072fe..3ae5d99196921 100644 --- a/mm/percpu.c +++ b/mm/percpu.c @@ -640,12 +640,13 @@ static void pcpu_block_update(struct pcpu_block_md *block, int start, int end) if (contig > block->contig_hint) { /* promote the old contig_hint to be the new scan_hint */ - if (start > block->contig_hint_start) { + if (block->contig_hint && start > block->contig_hint_start) { if (block->contig_hint > block->scan_hint) { block->scan_hint_start = block->contig_hint_start; block->scan_hint = block->contig_hint; - } else if (start < block->scan_hint_start) { + } else if (block->scan_hint && + start < block->scan_hint_start) { /* * The old contig_hint == scan_hint. But, the * new contig is larger so hold the invariant @@ -664,10 +665,12 @@ static void pcpu_block_update(struct pcpu_block_md *block, int start, int end) __ffs(start) > __ffs(block->contig_hint_start))) { /* start has a better alignment so use it */ block->contig_hint_start = start; - if (start < block->scan_hint_start && + if (block->scan_hint && + start < block->scan_hint_start && block->contig_hint > block->scan_hint) block->scan_hint = 0; - } else if (start > block->scan_hint_start || + } else if ((block->scan_hint && + start > block->scan_hint_start) || block->contig_hint > block->scan_hint) { /* * Knowing contig == contig_hint, update the scan_hint @@ -845,7 +848,8 @@ static void pcpu_block_update_hint_alloc(struct pcpu_chunk *chunk, int bit_off, PCPU_BITMAP_BLOCK_BITS, s_off + bits); - if (pcpu_region_overlap(s_block->scan_hint_start, + if (s_block->scan_hint && + pcpu_region_overlap(s_block->scan_hint_start, s_block->scan_hint_start + s_block->scan_hint, s_off, s_off + bits)) @@ -889,7 +893,8 @@ static void pcpu_block_update_hint_alloc(struct pcpu_chunk *chunk, int bit_off, /* reset the block */ e_block++; } else { - if (e_off > e_block->scan_hint_start) + if (e_block->scan_hint && + e_off > e_block->scan_hint_start) e_block->scan_hint = 0; e_block->left_free = 0; @@ -922,7 +927,8 @@ static void pcpu_block_update_hint_alloc(struct pcpu_chunk *chunk, int bit_off, if (nr_empty_pages) pcpu_update_empty_pages(chunk, -nr_empty_pages); - if (pcpu_region_overlap(chunk_md->scan_hint_start, + if (chunk_md->scan_hint && + pcpu_region_overlap(chunk_md->scan_hint_start, chunk_md->scan_hint_start + chunk_md->scan_hint, bit_off, |
