FAILED: patch "[PATCH] mm/mempool: fix poisoning order>0 pages with HIGHMEM" failed to apply to 6.6-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 6.6-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.6.y
git checkout FETCH_HEAD
git cherry-pick -x ec33b59542d96830e3c89845ff833cf7b25ef172
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2025112434-uncle-ethics-cb16@gregkh' --subject-prefix 'PATCH 6.6.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From ec33b59542d96830e3c89845ff833cf7b25ef172 Mon Sep 17 00:00:00 2001
From: Vlastimil Babka <[email protected]>
Date: Thu, 13 Nov 2025 19:54:35 +0100
Subject: [PATCH] mm/mempool: fix poisoning order>0 pages with HIGHMEM
The kernel test has reported:
BUG: unable to handle page fault for address: fffba000 #PF: supervisor write access in kernel mode #PF: error_code(0x0002) - not-present page *pde = 03171067 *pte = 00000000 Oops: Oops: 0002 [#1] CPU: 0 UID: 0 PID: 1 Comm: swapper/0 Tainted: G T 6.18.0-rc2-00031-gec7f31b2a2d3 #1 NONE a1d066dfe789f54bc7645c7989957d2bdee593ca Tainted: [T]=RANDSTRUCT Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 EIP: memset (arch/x86/include/asm/string_32.h:168 arch/x86/lib/memcpy_32.c:17) Code: a5 8b 4d f4 83 e1 03 74 02 f3 a4 83 c4 04 5e 5f 5d 2e e9 73 41 01 00 90 90 90 3e 8d 74 26 00 55 89 e5 57 56 89 c6 89 d0 89 f7 <f3> aa 89 f0 5e 5f 5d 2e e9 53 41 01 00 cc cc cc 55 89 e5 53 57 56 EAX: 0000006b EBX: 00000015 ECX: 001fefff EDX: 0000006b ESI: fffb9000 EDI: fffba000 EBP: c611fbf0 ESP: c611fbe8 DS: 007b ES: 007b FS: 0000 GS: 0000 SS: 0068 EFLAGS: 00010287 CR0: 80050033 CR2: fffba000 CR3: 0316e000 CR4: 00040690 Call Trace: poison_element (mm/mempool.c:83 mm/mempool.c:102) mempool_init_node (mm/mempool.c:142 mm/mempool.c:226) mempool_init_noprof (mm/mempool.c:250 (discriminator 1)) ? mempool_alloc_pages (mm/mempool.c:640) bio_integrity_initfn (block/bio-integrity.c:483 (discriminator 8)) ? mempool_alloc_pages (mm/mempool.c:640) do_one_initcall (init/main.c:1283)
Christoph found out this is due to the poisoning code not dealing properly with CONFIG_HIGHMEM because only the first page is mapped but then the whole potentially high-order page is accessed.
We could give up on HIGHMEM here, but it's straightforward to fix this with a loop that's mapping, poisoning or checking and unmapping individual pages.
mm/mempool.c +26 -6
@@ -68,10 +68,20 @@ static void check_element(mempool_t *pool, void *element) }else if (pool->free == mempool_free_pages) {/* Mempools backed by page allocator */ int order = (int )(long )pool->pool_data; -void *addr =kmap_local_page ((struct page *)element); -__check_element (pool, addr,1UL << (PAGE_SHIFT + order)); -kunmap_local (addr); +#ifdef CONFIG_HIGHMEM +for (int i =0 ; i < (1 << order); i++) { +struct page *page = (struct page *)element; +void *addr =kmap_local_page (page + i); + +__check_element (pool, addr,PAGE_SIZE ); +kunmap_local (addr); + } +#else +void *addr =page_address ((struct page *)element); + +__check_element (pool, addr,PAGE_SIZE << order); +#endif } }
@@ -97,10 +107,20 @@ static void poison_element(mempool_t *pool, void *element) } else if (pool->alloc == mempool_alloc_pages) {/* Mempools backed by page allocator */ int order = (int )(long )pool->pool_data; -void *addr =kmap_local_page ((struct page *)element); -__poison_element (addr,1UL << (PAGE_SHIFT + order)); -kunmap_local (addr); +#ifdef CONFIG_HIGHMEM +for (int i =0 ; i < (1 << order); i++) { +struct page *page = (struct page *)element; +void *addr =kmap_local_page (page + i); + +__poison_element (addr,PAGE_SIZE ); +kunmap_local (addr); + } +#else +void *addr =page_address ((struct page *)element); + +__poison_element (addr,PAGE_SIZE << order); +#endif } }#else /* CONFIG_SLUB_DEBUG_ON */
Sasha Levin
maintainerPATCH 1/2 mm/mempool: replace kmap_atomic() with kmap_local_page()
From: "Fabio M. De Francesco" <[email protected]>
[ Upstream commit f2bcc99a5e901a13b754648d1dbab60f4adf9375 ]
kmap_atomic() has been deprecated in favor of kmap_local_page().
Therefore, replace kmap_atomic() with kmap_local_page().
kmap_atomic() is implemented like a kmap_local_page() which also disables page-faults and preemption (the latter only in !PREEMPT_RT kernels). The kernel virtual addresses returned by these two API are only valid in the context of the callers (i.e., they cannot be handed to other threads).
With kmap_local_page() the mappings are per thread and CPU local like in kmap_atomic(); however, they can handle page-faults and can be called from any context (including interrupts). The tasks that call kmap_local_page() can be preempted and, when they are scheduled to run again, the kernel virtual addresses are restored and are still valid.
The code blocks between the mappings and un-mappings don't rely on the above-mentioned side effects of kmap_atomic(), so that mere replacements of the old API with the new one is all that they require (i.e., there is no need to explicitly call pagefault_disable() and/or preempt_disable()).
Stable-dep-of: ec33b59542d9 ("mm/mempool: fix poisoning order>0 pages with HIGHMEM")
--- mm/mempool.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
mm/mempool.c +4 -4
@@ -64,10 +64,10 @@ static void check_element(mempool_t *pool, void *element) }else if (pool->free == mempool_free_pages) {/* Mempools backed by page allocator */ int order = (int )(long )pool->pool_data; -void *addr =kmap_atomic ((struct page *)element); +void *addr =kmap_local_page ((struct page *)element);__check_element (pool, addr,1UL << (PAGE_SHIFT + order)); -kunmap_atomic (addr); +kunmap_local (addr); } }
@@ -89,10 +89,10 @@ static void poison_element(mempool_t *pool, void *element) } else if (pool->alloc == mempool_alloc_pages) {/* Mempools backed by page allocator */ int order = (int )(long )pool->pool_data; -void *addr =kmap_atomic ((struct page *)element); +void *addr =kmap_local_page ((struct page *)element);__poison_element (addr,1UL << (PAGE_SHIFT + order)); -kunmap_atomic (addr); +kunmap_local (addr); } }#else /* CONFIG_DEBUG_SLAB || CONFIG_SLUB_DEBUG_ON */
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 2/2 mm/mempool: fix poisoning order>0 pages with HIGHMEM
From: Vlastimil Babka <[email protected]>
[ Upstream commit ec33b59542d96830e3c89845ff833cf7b25ef172 ]
The kernel test has reported:
BUG: unable to handle page fault for address: fffba000 #PF: supervisor write access in kernel mode #PF: error_code(0x0002) - not-present page *pde = 03171067 *pte = 00000000 Oops: Oops: 0002 [#1] CPU: 0 UID: 0 PID: 1 Comm: swapper/0 Tainted: G T 6.18.0-rc2-00031-gec7f31b2a2d3 #1 NONE a1d066dfe789f54bc7645c7989957d2bdee593ca Tainted: [T]=RANDSTRUCT Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 EIP: memset (arch/x86/include/asm/string_32.h:168 arch/x86/lib/memcpy_32.c:17) Code: a5 8b 4d f4 83 e1 03 74 02 f3 a4 83 c4 04 5e 5f 5d 2e e9 73 41 01 00 90 90 90 3e 8d 74 26 00 55 89 e5 57 56 89 c6 89 d0 89 f7 <f3> aa 89 f0 5e 5f 5d 2e e9 53 41 01 00 cc cc cc 55 89 e5 53 57 56 EAX: 0000006b EBX: 00000015 ECX: 001fefff EDX: 0000006b ESI: fffb9000 EDI: fffba000 EBP: c611fbf0 ESP: c611fbe8 DS: 007b ES: 007b FS: 0000 GS: 0000 SS: 0068 EFLAGS: 00010287 CR0: 80050033 CR2: fffba000 CR3: 0316e000 CR4: 00040690 Call Trace: poison_element (mm/mempool.c:83 mm/mempool.c:102) mempool_init_node (mm/mempool.c:142 mm/mempool.c:226) mempool_init_noprof (mm/mempool.c:250 (discriminator 1)) ? mempool_alloc_pages (mm/mempool.c:640) bio_integrity_initfn (block/bio-integrity.c:483 (discriminator 8)) ? mempool_alloc_pages (mm/mempool.c:640) do_one_initcall (init/main.c:1283)
Christoph found out this is due to the poisoning code not dealing properly with CONFIG_HIGHMEM because only the first page is mapped but then the whole potentially high-order page is accessed.
We could give up on HIGHMEM here, but it's straightforward to fix this with a loop that's mapping, poisoning or checking and unmapping individual pages.
--- mm/mempool.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-)
mm/mempool.c +26 -6
@@ -64,10 +64,20 @@ static void check_element(mempool_t *pool, void *element) }else if (pool->free == mempool_free_pages) {/* Mempools backed by page allocator */ int order = (int )(long )pool->pool_data; -void *addr =kmap_local_page ((struct page *)element); -__check_element (pool, addr,1UL << (PAGE_SHIFT + order)); -kunmap_local (addr); +#ifdef CONFIG_HIGHMEM +for (int i =0 ; i < (1 << order); i++) { +struct page *page = (struct page *)element; +void *addr =kmap_local_page (page + i); + +__check_element (pool, addr,PAGE_SIZE ); +kunmap_local (addr); + } +#else +void *addr =page_address ((struct page *)element); + +__check_element (pool, addr,PAGE_SIZE << order); +#endif } }
@@ -89,10 +99,20 @@ static void poison_element(mempool_t *pool, void *element) } else if (pool->alloc == mempool_alloc_pages) {/* Mempools backed by page allocator */ int order = (int )(long )pool->pool_data; -void *addr =kmap_local_page ((struct page *)element); -__poison_element (addr,1UL << (PAGE_SHIFT + order)); -kunmap_local (addr); +#ifdef CONFIG_HIGHMEM +for (int i =0 ; i < (1 << order); i++) { +struct page *page = (struct page *)element; +void *addr =kmap_local_page (page + i); + +__poison_element (addr,PAGE_SIZE ); +kunmap_local (addr); + } +#else +void *addr =page_address ((struct page *)element); + +__poison_element (addr,PAGE_SIZE << order); +#endif } }#else /* CONFIG_DEBUG_SLAB || CONFIG_SLUB_DEBUG_ON */
Signature · 1 line
2.51.0