Skip to contentSkip to conversation

Handle warning of allocation failure on DMA zone w/o managed pages

PATCH Applied Baoquan He 5 participants 13 messages Dec 23, 2021 – Jan 12, 2022

Subsystems (7)
lore
Share & tools
lore

Baoquan He

author
#0 lore raw

v4 cover Handle warning of allocation failure on DMA zone w/o managed pages

**Problem observed:
On x86_64, when crash is triggered and entering into kdump kernel, page allocation failure can always be seen.

---------------------------------
DMA: preallocated 128 KiB GFP_KERNEL pool for atomic allocations
swapper/0: page allocation failure: order:5, mode:0xcc1(GFP_KERNEL|GFP_DMA), nodemask=(null),cpuset=/,mems_allowed=0

 CPU: 0 PID: 1 Comm: swapper/0
 Call Trace:
  dump_stack+0x7f/0xa1
  warn_alloc.cold+0x72/0xd6
  ......
  __alloc_pages+0x24d/0x2c0
  ......
  dma_atomic_pool_init+0xdb/0x176
  do_one_initcall+0x67/0x320
  ? rcu_read_lock_sched_held+0x3f/0x80
  kernel_init_freeable+0x290/0x2dc
  ? rest_init+0x24f/0x24f
  kernel_init+0xa/0x111
  ret_from_fork+0x22/0x30
 Mem-Info:
 ------------------------------------

***Root cause:
In the current kernel, it assumes that DMA zone must have managed pages and try to request pages if CONFIG_ZONE_DMA is enabled. While this is not always true. E.g in kdump kernel of x86_64, only low 1M is presented and locked down at very early stage of boot, so that this low 1M won't be added into buddy allocator to become managed pages of DMA zone. This exception will always cause page allocation failure if page is requested from DMA zone.

***Investigation:
This failure happens since below commit merged into linus's tree.
1a6a9044b967 x86/setup: Remove CONFIG_X86_RESERVE_LOW and reservelow= options 23721c8e92f7 x86/crash: Remove crash_reserve_low_1M()
f1d4d47c5851 x86/setup: Always reserve the first 1M of RAM
7c321eb2b843 x86/kdump: Remove the backup region handling
6f599d84231f x86/kdump: Always reserve the low 1M when the crashkernel option is specified

Before them, on x86_64, the low 640K area will be reused by kdump kernel. So in kdump kernel, the content of low 640K area is copied into a backup region for dumping before jumping into kdump. Then except of those firmware reserved region in [0, 640K], the left area will be added into buddy allocator to become available managed pages of DMA zone.

However, after above commits applied, in kdump kernel of x86_64, the low 1M is reserved by memblock, but not released to buddy allocator. So any later page allocation requested from DMA zone will fail.

At the beginning, if crashkernel is reserved, the low 1M need be locked down because AMD SME encrypts memory making the old backup region mechanims impossible when switching into kdump kernel.

Later, it was also observed that there are BIOSes corrupting memory under 1M. To solve this, in commit f1d4d47c5851, the entire region of low 1M is always reserved after the real mode trampoline is allocated.

Besides, recently, Intel engineer mentioned their TDX (Trusted domain extensions) which is under development in kernel also needs to lock down the low 1M. So we can't simply revert above commits to fix the page allocation failure from DMA zone as someone suggested.

***Solution:
Currently, only DMA atomic pool and dma-kmalloc will initialize and request page allocation with GFP_DMA during bootup.

So only initializ DMA atomic pool when DMA zone has available managed pages, otherwise just skip the initialization.

For dma-kmalloc(), for the time being, let's mute the warning of allocation failure if requesting pages from DMA zone while no manged pages. Meanwhile, change code to use dma_alloc_xx/dma_map_xx API to replace kmalloc(GFP_DMA), or do not use GFP_DMA when calling kmalloc() if not necessary. Christoph is posting patches to fix those under drivers/scsi/. Finally, we can remove the need of dma-kmalloc() as people suggested.

Changelog:
v3->v4:
- Split the old v3 into two separate patchset. The first two clean up/improvement patches in v3 have been sent out in a independent patchset. The fixes patchs are adapted and sent in this patchset.
- Do not change dma-kmalloc(), mute the warning of allocation failure instead if it's requesting page from DMA zone which has no managed pages.

v2-Resend -> v3:
- Re-implement has_managed_dma() according to David's suggestion.
- Add Fixes tag and cc stable.

v2->v2 RESEND:
- John pinged to push the repost of this patchset. So fix one typo of suject of patch 3/5; Fix a building error caused by mix declaration in patch 5/5. Both of them are found by John from his testing.
- Rewrite cover letter to add more information.

v1->v2:
Change to check if managed DMA zone exists. If DMA zone has managed pages, go further to request page from DMA zone to initialize. Otherwise, just skip to initialize stuffs which need pages from DMA zone.

v3:
https://lore.kernel.org/all/[email protected]/T/#u

V2 RESEND post:
https://lore.kernel.org/all/[email protected]/T/#u

v2 post:
https://lore.kernel.org/all/[email protected]/T/#u

v1 post:
https://lore.kernel.org/all/[email protected]/T/#u

Baoquan He (3):
mm_zone: add function to check if managed dma zone exists dma/pool: create dma atomic pool only if dma zone has managed pages mm/page_alloc.c: do not warn allocation failure on zone DMA if no
managed pages

 include/linux/mmzone.h |  9 +++++++++
 kernel/dma/pool.c      |  4 ++--
 mm/page_alloc.c        | 18 +++++++++++++++++-
 3 files changed, 28 insertions(+), 3 deletions(-)
Signature · 1 line
2.26.3
author
#1 lore raw

PATCH v4 1/3 mm_zone: add function to check if managed dma zone exists

In some places of the current kernel, it assumes that dma zone must have managed pages if CONFIG_ZONE_DMA is enabled. While this is not always true. E.g in kdump kernel of x86_64, only low 1M is presented and locked down at very early stage of boot, so that there's no managed pages at all in DMA zone. This exception will always cause page allocation failure if page is requested from DMA zone.

Here add function has_managed_dma() and the relevant helper functions to check if there's DMA zone with managed pages. It will be used in later patches.

Fixes 6f599d84231f ("x86/kdump: Always reserve the low 1M when the crashkernel option is specified")
---
 include/linux/mmzone.h |  9 +++++++++
 mm/page_alloc.c        | 15 +++++++++++++++
 2 files changed, 24 insertions(+)
include/linux/mmzone.h +9 -0
index 58e744b78c2c..6e1b726e9adf 100644
@@ -1046,6 +1046,15 @@ static inline int is_highmem_idx(enum zone_type idx)
 #endif
 }
 
+#ifdef CONFIG_ZONE_DMA
+bool has_managed_dma(void);
+#else
+static inline bool has_managed_dma(void)
+{
+	return false;
+}
+#endif
+
 /**
  * is_highmem - helper function to quickly check if a struct zone is a
  *              highmem zone or not.  This is an attempt to keep references
mm/page_alloc.c +15 -0
index c5952749ad40..7c7a0b5de2ff 100644
@@ -9460,3 +9460,18 @@ bool take_page_off_buddy(struct page *page)
 	return ret;
 }
 #endif
+
+#ifdef CONFIG_ZONE_DMA
+bool has_managed_dma(void)
+{
+	struct pglist_data *pgdat;
+
+	for_each_online_pgdat(pgdat) {
+		struct zone *zone = &pgdat->node_zones[ZONE_DMA];
+
+		if (managed_zone(zone))
+			return true;
+	}
+	return false;
+}
+#endif /* CONFIG_ZONE_DMA */
Signature · 1 line
2.26.3
Acked-by on v4 1/3
#2 lore raw

Re: [PATCH v4 1/3] mm_zone: add function to check if managed dma zone exists

Quoted 7 lines · Baoquan He

In some places of the current kernel, it assumes that dma zone must have managed pages if CONFIG_ZONE_DMA is enabled. While this is not always true. E.g in kdump kernel of x86_64, only low 1M is presented and locked down at very early stage of boot, so that there's no managed pages at all in DMA zone. This exception will always cause page allocation failure if page is requested from DMA zone.

Quoted 8 lines

Here add function has_managed_dma() and the relevant helper functions to check if there's DMA zone with managed pages. It will be used in later patches.

Fixes 6f599d84231f ("x86/kdump: Always reserve the low 1M when the crashkernel option is specified")
Quoted 48 lines
---
  include/linux/mmzone.h |  9 +++++++++
  mm/page_alloc.c        | 15 +++++++++++++++
  2 files changed, 24 insertions(+)
include/linux/mmzone.h +9 -0
index 58e744b78c2c..6e1b726e9adf 100644
@@ -1046,6 +1046,15 @@ static inline int is_highmem_idx(enum zone_type idx)
  #endif
  }
 
+#ifdef CONFIG_ZONE_DMA
+bool has_managed_dma(void);
+#else
+static inline bool has_managed_dma(void)
+{
+	return false;
+}
+#endif
+
  /**
   * is_highmem - helper function to quickly check if a struct zone is a
   *              highmem zone or not.  This is an attempt to keep references
mm/page_alloc.c +15 -0
index c5952749ad40..7c7a0b5de2ff 100644
@@ -9460,3 +9460,18 @@ bool take_page_off_buddy(struct page *page)
  	return ret;
  }
  #endif
+
+#ifdef CONFIG_ZONE_DMA
+bool has_managed_dma(void)
+{
+	struct pglist_data *pgdat;
+
+	for_each_online_pgdat(pgdat) {
+		struct zone *zone = &pgdat->node_zones[ZONE_DMA];
+
+		if (managed_zone(zone))
+			return true;
+	}
+	return false;
+}
+#endif /* CONFIG_ZONE_DMA */
author
#3 lore raw

PATCH v4 2/3 dma/pool: create dma atomic pool only if dma zone has managed pages

In reply to Baoquan He

Currently three dma atomic pools are initialized as long as the relevant kernel codes are built in. While in kdump kernel of x86_64, this is not right when trying to create atomic_pool_dma, because there's no managed pages in DMA zone. In the case, DMA zone only has low 1M memory presented and locked down by memblock allocator. So no pages are added into buddy of DMA zone. Please check commit f1d4d47c5851 ("x86/setup: Always reserve the first 1M of RAM").

Then in kdump kernel of x86_64, it always prints below failure message:

DMA: preallocated 128 KiB GFP_KERNEL pool for atomic allocations
swapper/0: page allocation failure: order:5, mode:0xcc1(GFP_KERNEL|GFP_DMA), nodemask=(null),cpuset=/,mems_allowed=0

 CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.13.0-0.rc5.20210611git929d931f2b40.42.fc35.x86_64 #1
 Hardware name: Dell Inc. PowerEdge R910/0P658H, BIOS 2.12.0 06/04/2018
 Call Trace:
  dump_stack+0x7f/0xa1
  warn_alloc.cold+0x72/0xd6
  ? _raw_spin_unlock_irq+0x24/0x40
  ? __alloc_pages_direct_compact+0x90/0x1b0
  __alloc_pages_slowpath.constprop.0+0xf29/0xf50
  ? __cond_resched+0x16/0x50
  ? prepare_alloc_pages.constprop.0+0x19d/0x1b0
  __alloc_pages+0x24d/0x2c0
  ? __dma_atomic_pool_init+0x93/0x93
  alloc_page_interleave+0x13/0xb0
  atomic_pool_expand+0x118/0x210
  ? __dma_atomic_pool_init+0x93/0x93
  __dma_atomic_pool_init+0x45/0x93
  dma_atomic_pool_init+0xdb/0x176
  do_one_initcall+0x67/0x320
  ? rcu_read_lock_sched_held+0x3f/0x80
  kernel_init_freeable+0x290/0x2dc
  ? rest_init+0x24f/0x24f
  kernel_init+0xa/0x111
  ret_from_fork+0x22/0x30
 Mem-Info:
 ......
 DMA: failed to allocate 128 KiB GFP_KERNEL|GFP_DMA pool for atomic allocation
 DMA: preallocated 128 KiB GFP_KERNEL|GFP_DMA32 pool for atomic allocations

Here, let's check if DMA zone has managed pages, then create atomic_pool_dma if yes. Otherwise just skip it.

Fixes 6f599d84231f ("x86/kdump: Always reserve the low 1M when the crashkernel option is specified")
Cc Christoph Hellwig <[email protected]>
Cc Marek Szyprowski <[email protected]>
Cc Robin Murphy <[email protected]>
---
 kernel/dma/pool.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
kernel/dma/pool.c +2 -2
index 5a85804b5beb..00df3edd6c5d 100644
@@ -206,7 +206,7 @@ static int __init dma_atomic_pool_init(void)
 						    GFP_KERNEL);
 	if (!atomic_pool_kernel)
 		ret = -ENOMEM;
-	if (IS_ENABLED(CONFIG_ZONE_DMA)) {
+	if (has_managed_dma()) {
 		atomic_pool_dma = __dma_atomic_pool_init(atomic_pool_size,
 						GFP_KERNEL | GFP_DMA);
 		if (!atomic_pool_dma)
@@ -229,7 +229,7 @@ static inline struct gen_pool *dma_guess_pool(struct gen_pool *prev, gfp_t gfp)
 	if (prev == NULL) {
 		if (IS_ENABLED(CONFIG_ZONE_DMA32) && (gfp & GFP_DMA32))
 			return atomic_pool_dma32;
-		if (IS_ENABLED(CONFIG_ZONE_DMA) && (gfp & GFP_DMA))
+		if (atomic_pool_dma && (gfp & GFP_DMA))
 			return atomic_pool_dma;
 		return atomic_pool_kernel;
 	}
Signature · 1 line
2.26.3
Acked-by on v4 2/3
#5 lore raw

Re: [PATCH v4 2/3] dma/pool: create dma atomic pool only if dma zone has managed pages

In reply to Baoquan He
Quoted 40 lines · Baoquan He

Currently three dma atomic pools are initialized as long as the relevant kernel codes are built in. While in kdump kernel of x86_64, this is not right when trying to create atomic_pool_dma, because there's no managed pages in DMA zone. In the case, DMA zone only has low 1M memory presented and locked down by memblock allocator. So no pages are added into buddy of DMA zone. Please check commit f1d4d47c5851 ("x86/setup: Always reserve the first 1M of RAM").

Then in kdump kernel of x86_64, it always prints below failure message:

DMA: preallocated 128 KiB GFP_KERNEL pool for atomic allocations
swapper/0: page allocation failure: order:5, mode:0xcc1(GFP_KERNEL|GFP_DMA), nodemask=(null),cpuset=/,mems_allowed=0

  CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.13.0-0.rc5.20210611git929d931f2b40.42.fc35.x86_64 #1
  Hardware name: Dell Inc. PowerEdge R910/0P658H, BIOS 2.12.0 06/04/2018
  Call Trace:
   dump_stack+0x7f/0xa1
   warn_alloc.cold+0x72/0xd6
   ? _raw_spin_unlock_irq+0x24/0x40
   ? __alloc_pages_direct_compact+0x90/0x1b0
   __alloc_pages_slowpath.constprop.0+0xf29/0xf50
   ? __cond_resched+0x16/0x50
   ? prepare_alloc_pages.constprop.0+0x19d/0x1b0
   __alloc_pages+0x24d/0x2c0
   ? __dma_atomic_pool_init+0x93/0x93
   alloc_page_interleave+0x13/0xb0
   atomic_pool_expand+0x118/0x210
   ? __dma_atomic_pool_init+0x93/0x93
   __dma_atomic_pool_init+0x45/0x93
   dma_atomic_pool_init+0xdb/0x176
   do_one_initcall+0x67/0x320
   ? rcu_read_lock_sched_held+0x3f/0x80
   kernel_init_freeable+0x290/0x2dc
   ? rest_init+0x24f/0x24f
   kernel_init+0xa/0x111
   ret_from_fork+0x22/0x30
  Mem-Info:
  ......
  DMA: failed to allocate 128 KiB GFP_KERNEL|GFP_DMA pool for atomic allocation
  DMA: preallocated 128 KiB GFP_KERNEL|GFP_DMA32 pool for atomic allocations
Quoted 6 lines

Here, let's check if DMA zone has managed pages, then create atomic_pool_dma if yes. Otherwise just skip it.

Fixes 6f599d84231f ("x86/kdump: Always reserve the low 1M when the crashkernel option is specified")
Quoted 30 lines
Cc Christoph Hellwig <[email protected]>
Cc Marek Szyprowski <[email protected]>
Cc Robin Murphy <[email protected]>
---
  kernel/dma/pool.c | 4 ++--
  1 file changed, 2 insertions(+), 2 deletions(-)
kernel/dma/pool.c +2 -2
index 5a85804b5beb..00df3edd6c5d 100644
@@ -206,7 +206,7 @@ static int __init dma_atomic_pool_init(void)
  						    GFP_KERNEL);
  	if (!atomic_pool_kernel)
  		ret = -ENOMEM;
-	if (IS_ENABLED(CONFIG_ZONE_DMA)) {
+	if (has_managed_dma()) {
  		atomic_pool_dma = __dma_atomic_pool_init(atomic_pool_size,
  						GFP_KERNEL | GFP_DMA);
  		if (!atomic_pool_dma)
@@ -229,7 +229,7 @@ static inline struct gen_pool *dma_guess_pool(struct gen_pool *prev, gfp_t gfp)
  	if (prev == NULL) {
  		if (IS_ENABLED(CONFIG_ZONE_DMA32) && (gfp & GFP_DMA32))
  			return atomic_pool_dma32;
-		if (IS_ENABLED(CONFIG_ZONE_DMA) && (gfp & GFP_DMA))
+		if (atomic_pool_dma && (gfp & GFP_DMA))
  			return atomic_pool_dma;
  		return atomic_pool_kernel;
  	}
Reviewed-by on v4 2/3
#6 lore raw

Re: [PATCH v4 2/3] dma/pool: create dma atomic pool only if dma zone has managed pages

In reply to Baoquan He
Quoted 68 lines · Baoquan He

Currently three dma atomic pools are initialized as long as the relevant kernel codes are built in. While in kdump kernel of x86_64, this is not right when trying to create atomic_pool_dma, because there's no managed pages in DMA zone. In the case, DMA zone only has low 1M memory presented and locked down by memblock allocator. So no pages are added into buddy of DMA zone. Please check commit f1d4d47c5851 ("x86/setup: Always reserve the first 1M of RAM").

Then in kdump kernel of x86_64, it always prints below failure message:

DMA: preallocated 128 KiB GFP_KERNEL pool for atomic allocations
swapper/0: page allocation failure: order:5, mode:0xcc1(GFP_KERNEL|GFP_DMA), nodemask=(null),cpuset=/,mems_allowed=0

 CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.13.0-0.rc5.20210611git929d931f2b40.42.fc35.x86_64 #1
 Hardware name: Dell Inc. PowerEdge R910/0P658H, BIOS 2.12.0 06/04/2018
 Call Trace:
  dump_stack+0x7f/0xa1
  warn_alloc.cold+0x72/0xd6
  ? _raw_spin_unlock_irq+0x24/0x40
  ? __alloc_pages_direct_compact+0x90/0x1b0
  __alloc_pages_slowpath.constprop.0+0xf29/0xf50
  ? __cond_resched+0x16/0x50
  ? prepare_alloc_pages.constprop.0+0x19d/0x1b0
  __alloc_pages+0x24d/0x2c0
  ? __dma_atomic_pool_init+0x93/0x93
  alloc_page_interleave+0x13/0xb0
  atomic_pool_expand+0x118/0x210
  ? __dma_atomic_pool_init+0x93/0x93
  __dma_atomic_pool_init+0x45/0x93
  dma_atomic_pool_init+0xdb/0x176
  do_one_initcall+0x67/0x320
  ? rcu_read_lock_sched_held+0x3f/0x80
  kernel_init_freeable+0x290/0x2dc
  ? rest_init+0x24f/0x24f
  kernel_init+0xa/0x111
  ret_from_fork+0x22/0x30
 Mem-Info:
 ......
 DMA: failed to allocate 128 KiB GFP_KERNEL|GFP_DMA pool for atomic allocation
 DMA: preallocated 128 KiB GFP_KERNEL|GFP_DMA32 pool for atomic allocations

Here, let's check if DMA zone has managed pages, then create atomic_pool_dma if yes. Otherwise just skip it.

Fixes 6f599d84231f ("x86/kdump: Always reserve the low 1M when the crashkernel option is specified")
Cc stable at vger.kernel.org
Cc Christoph Hellwig <[email protected]>
Cc Marek Szyprowski <[email protected]>
Cc Robin Murphy <[email protected]>
Cc iommu at lists.linux-foundation.org
---
 kernel/dma/pool.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
kernel/dma/pool.c +1 -1
index 5a85804b5beb..00df3edd6c5d 100644
@@ -206,7 +206,7 @@ static int __init dma_atomic_pool_init(void)
 						    GFP_KERNEL);
 	if (!atomic_pool_kernel)
 		ret = -ENOMEM;
-	if (IS_ENABLED(CONFIG_ZONE_DMA)) {
+	if (has_managed_dma()) {
 		atomic_pool_dma = __dma_atomic_pool_init(atomic_pool_size,
 						GFP_KERNEL | GFP_DMA);
 		if (!atomic_pool_dma)

kernel/dma/pool.c static inline struct gen_pool *dma_guess_pool(struct gen_pool *prev, gfp_t gfp) · line 235

Quoted 8 lines
kernel/dma/pool.c +1 -1
@@ -229,7 +229,7 @@ static inline struct gen_pool *dma_guess_pool(struct gen_pool *prev, gfp_t gfp)
 	if (prev == NULL) {
 		if (IS_ENABLED(CONFIG_ZONE_DMA32) && (gfp & GFP_DMA32))
 			return atomic_pool_dma32;
-		if (IS_ENABLED(CONFIG_ZONE_DMA) && (gfp & GFP_DMA))
+		if (atomic_pool_dma && (gfp & GFP_DMA))
 			return atomic_pool_dma;
 		return atomic_pool_kernel;
 	}

I thought for a second that we might have to tweak atomic_pool_work_fn(), but atomic_pool_resize() handles it properly already.

Signature · 3 lines
Thanks,

David / dhildenb
author
#7 lore raw

PATCH v4 3/3 mm/page_alloc.c: do not warn allocation failure on zone DMA if no managed pages

In reply to Baoquan He

In kdump kernel of x86_64, page allocation failure is observed:

kworker/u2:2: page allocation failure: order:0, mode:0xcc1(GFP_KERNEL|GFP_DMA), nodemask=(null),cpuset=/,mems_allowed=0

 CPU: 0 PID: 55 Comm: kworker/u2:2 Not tainted 5.16.0-rc4+ #5
 Hardware name: AMD Dinar/Dinar, BIOS RDN1505B 06/05/2013
 Workqueue: events_unbound async_run_entry_fn
 Call Trace:
  <TASK>
  dump_stack_lvl+0x48/0x5e
  warn_alloc.cold+0x72/0xd6
  __alloc_pages_slowpath.constprop.0+0xc69/0xcd0
  __alloc_pages+0x1df/0x210
  new_slab+0x389/0x4d0
  ___slab_alloc+0x58f/0x770
  __slab_alloc.constprop.0+0x4a/0x80
  kmem_cache_alloc_trace+0x24b/0x2c0
  sr_probe+0x1db/0x620
  ......
  device_add+0x405/0x920
  ......
  __scsi_add_device+0xe5/0x100
  ata_scsi_scan_host+0x97/0x1d0
  async_run_entry_fn+0x30/0x130
  process_one_work+0x1e8/0x3c0
  worker_thread+0x50/0x3b0
  ? rescuer_thread+0x350/0x350
  kthread+0x16b/0x190
  ? set_kthread_struct+0x40/0x40
  ret_from_fork+0x22/0x30
  </TASK>
 Mem-Info:
 ......

The above failure happened when calling kmalloc() to allocate buffer with GFP_DMA. It requests to allocate slab page from DMA zone while no managed pages at all in there.
sr_probe()
--> get_capabilities()

     --> buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);

Because in the current kernel, dma-kmalloc will be created as long as CONFIG_ZONE_DMA is enabled. However, kdump kernel of x86_64 doesn't have managed pages on DMA zone since commit 6f599d84231f ("x86/kdump: Always reserve the low 1M when the crashkernel option is specified"). The failure can be always reproduced.

For now, let's mute the warning of allocation failure if requesting pages from DMA zone while no managed pages.

Fixes 6f599d84231f ("x86/kdump: Always reserve the low 1M when the crashkernel option is specified")
Cc Christoph Lameter <[email protected]>
Cc Pekka Enberg <[email protected]>
Cc David Rientjes <[email protected]>
Cc Joonsoo Kim <[email protected]>
Cc Vlastimil Babka <[email protected]>
---
 mm/page_alloc.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
mm/page_alloc.c +2 -1
index 7c7a0b5de2ff..843bc8e5550a 100644
@@ -4204,7 +4204,8 @@ void warn_alloc(gfp_t gfp_mask, nodemask_t *nodemask, const char *fmt, ...)
 	va_list args;
 	static DEFINE_RATELIMIT_STATE(nopage_rs, 10*HZ, 1);
 
-	if ((gfp_mask & __GFP_NOWARN) || !__ratelimit(&nopage_rs))
+	if ((gfp_mask & __GFP_NOWARN) || !__ratelimit(&nopage_rs) ||
+		(gfp_mask & __GFP_DMA) && !has_managed_dma())
 		return;
 
 	va_start(args, fmt);
Signature · 1 line
2.26.3
Acked-by on v4 3/3
#8 lore raw

Re: [PATCH v4 3/3] mm/page_alloc.c: do not warn allocation failure on zone DMA if no managed pages

Quoted 46 lines · Baoquan He

In kdump kernel of x86_64, page allocation failure is observed:

kworker/u2:2: page allocation failure: order:0, mode:0xcc1(GFP_KERNEL|GFP_DMA), nodemask=(null),cpuset=/,mems_allowed=0

  CPU: 0 PID: 55 Comm: kworker/u2:2 Not tainted 5.16.0-rc4+ #5
  Hardware name: AMD Dinar/Dinar, BIOS RDN1505B 06/05/2013
  Workqueue: events_unbound async_run_entry_fn
  Call Trace:
   <TASK>
   dump_stack_lvl+0x48/0x5e
   warn_alloc.cold+0x72/0xd6
   __alloc_pages_slowpath.constprop.0+0xc69/0xcd0
   __alloc_pages+0x1df/0x210
   new_slab+0x389/0x4d0
   ___slab_alloc+0x58f/0x770
   __slab_alloc.constprop.0+0x4a/0x80
   kmem_cache_alloc_trace+0x24b/0x2c0
   sr_probe+0x1db/0x620
   ......
   device_add+0x405/0x920
   ......
   __scsi_add_device+0xe5/0x100
   ata_scsi_scan_host+0x97/0x1d0
   async_run_entry_fn+0x30/0x130
   process_one_work+0x1e8/0x3c0
   worker_thread+0x50/0x3b0
   ? rescuer_thread+0x350/0x350
   kthread+0x16b/0x190
   ? set_kthread_struct+0x40/0x40
   ret_from_fork+0x22/0x30
   </TASK>
  Mem-Info:
  ......

The above failure happened when calling kmalloc() to allocate buffer with GFP_DMA. It requests to allocate slab page from DMA zone while no managed pages at all in there.
sr_probe()
--> get_capabilities()

      --> buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);

Because in the current kernel, dma-kmalloc will be created as long as CONFIG_ZONE_DMA is enabled. However, kdump kernel of x86_64 doesn't have managed pages on DMA zone since commit 6f599d84231f ("x86/kdump: Always reserve the low 1M when the crashkernel option is specified"). The failure can be always reproduced.

Quoted 6 lines

For now, let's mute the warning of allocation failure if requesting pages from DMA zone while no managed pages.

Fixes 6f599d84231f ("x86/kdump: Always reserve the low 1M when the crashkernel option is specified")
Quoted 23 lines
Cc Christoph Lameter <[email protected]>
Cc Pekka Enberg <[email protected]>
Cc David Rientjes <[email protected]>
Cc Joonsoo Kim <[email protected]>
Cc Vlastimil Babka <[email protected]>
---
  mm/page_alloc.c | 3 ++-
  1 file changed, 2 insertions(+), 1 deletion(-)
mm/page_alloc.c +2 -1
index 7c7a0b5de2ff..843bc8e5550a 100644
@@ -4204,7 +4204,8 @@ void warn_alloc(gfp_t gfp_mask, nodemask_t *nodemask, const char *fmt, ...)
  	va_list args;
  	static DEFINE_RATELIMIT_STATE(nopage_rs, 10*HZ, 1);
 
-	if ((gfp_mask & __GFP_NOWARN) || !__ratelimit(&nopage_rs))
+	if ((gfp_mask & __GFP_NOWARN) || !__ratelimit(&nopage_rs) ||
+		(gfp_mask & __GFP_DMA) && !has_managed_dma())
  		return;
 
  	va_start(args, fmt);
Reviewed-by on v4 3/3
#9 lore raw

Re: [PATCH v4 3/3] mm/page_alloc.c: do not warn allocation failure on zone DMA if no managed pages

In reply to Baoquan He
Quoted 66 lines · Baoquan He

In kdump kernel of x86_64, page allocation failure is observed:

kworker/u2:2: page allocation failure: order:0, mode:0xcc1(GFP_KERNEL|GFP_DMA), nodemask=(null),cpuset=/,mems_allowed=0

 CPU: 0 PID: 55 Comm: kworker/u2:2 Not tainted 5.16.0-rc4+ #5
 Hardware name: AMD Dinar/Dinar, BIOS RDN1505B 06/05/2013
 Workqueue: events_unbound async_run_entry_fn
 Call Trace:
  <TASK>
  dump_stack_lvl+0x48/0x5e
  warn_alloc.cold+0x72/0xd6
  __alloc_pages_slowpath.constprop.0+0xc69/0xcd0
  __alloc_pages+0x1df/0x210
  new_slab+0x389/0x4d0
  ___slab_alloc+0x58f/0x770
  __slab_alloc.constprop.0+0x4a/0x80
  kmem_cache_alloc_trace+0x24b/0x2c0
  sr_probe+0x1db/0x620
  ......
  device_add+0x405/0x920
  ......
  __scsi_add_device+0xe5/0x100
  ata_scsi_scan_host+0x97/0x1d0
  async_run_entry_fn+0x30/0x130
  process_one_work+0x1e8/0x3c0
  worker_thread+0x50/0x3b0
  ? rescuer_thread+0x350/0x350
  kthread+0x16b/0x190
  ? set_kthread_struct+0x40/0x40
  ret_from_fork+0x22/0x30
  </TASK>
 Mem-Info:
 ......

The above failure happened when calling kmalloc() to allocate buffer with GFP_DMA. It requests to allocate slab page from DMA zone while no managed pages at all in there.
sr_probe()
--> get_capabilities()

     --> buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);

Because in the current kernel, dma-kmalloc will be created as long as CONFIG_ZONE_DMA is enabled. However, kdump kernel of x86_64 doesn't have managed pages on DMA zone since commit 6f599d84231f ("x86/kdump: Always reserve the low 1M when the crashkernel option is specified"). The failure can be always reproduced.

For now, let's mute the warning of allocation failure if requesting pages from DMA zone while no managed pages.

Fixes 6f599d84231f ("x86/kdump: Always reserve the low 1M when the crashkernel option is specified")
Cc Christoph Lameter <[email protected]>
Cc Pekka Enberg <[email protected]>
Cc David Rientjes <[email protected]>
Cc Joonsoo Kim <[email protected]>
Cc Vlastimil Babka <[email protected]>
---
 mm/page_alloc.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
mm/page_alloc.c +0 -0
index 7c7a0b5de2ff..843bc8e5550a 100644

mm/page_alloc.c void warn_alloc(gfp_t gfp_mask, nodemask_t *nodemask, const char *fmt, ...) · line 4210

Quoted 8 lines
mm/page_alloc.c +2 -1
@@ -4204,7 +4204,8 @@ void warn_alloc(gfp_t gfp_mask, nodemask_t *nodemask, const char *fmt, ...)
 	va_list args;
 	static DEFINE_RATELIMIT_STATE(nopage_rs, 10*HZ, 1);
 
-	if ((gfp_mask & __GFP_NOWARN) || !__ratelimit(&nopage_rs))
+	if ((gfp_mask & __GFP_NOWARN) || !__ratelimit(&nopage_rs) ||
+		(gfp_mask & __GFP_DMA) && !has_managed_dma())
 		return;
 

Warning when there's always no page in DMA zone is unnecessary and it confuses user.

The patch looks good.

And there is some driers that allocate memory with GFP_DMA even if that flag is unnecessary. We need to do cleanup later.

Baoquan Are you planning to do it soon?
I want to help that.

Merry Christmas,
Hyeonggon

Quoted 5 lines
mm/page_alloc.c +0 -0
 	va_start(args, fmt);
Signature · 1 line
2.26.3

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

author
#10 lore raw

Re: [PATCH v4 3/3] mm/page_alloc.c: do not warn allocation failure on zone DMA if no managed pages

Quoted 1 line · Hyeonggon Yoo

On Thu, Dec 23, 2021 at 05:44:35PM +0800, Baoquan He wrote:

......

Quoted 17 lines

mm/page_alloc.c void warn_alloc(gfp_t gfp_mask, nodemask_t *nodemask, const char *fmt, ...) · line 4210

Quoted 13 lines
mm/page_alloc.c +2 -1
index 7c7a0b5de2ff..843bc8e5550a 100644
@@ -4204,7 +4204,8 @@ void warn_alloc(gfp_t gfp_mask, nodemask_t *nodemask, const char *fmt, ...)
 	va_list args;
 	static DEFINE_RATELIMIT_STATE(nopage_rs, 10*HZ, 1);
 
-	if ((gfp_mask & __GFP_NOWARN) || !__ratelimit(&nopage_rs))
+	if ((gfp_mask & __GFP_NOWARN) || !__ratelimit(&nopage_rs) ||
+		(gfp_mask & __GFP_DMA) && !has_managed_dma())
 		return;
 

Warning when there's always no page in DMA zone is unnecessary and it confuses user.

Quoted 5 lines

The patch looks good.

And there is some driers that allocate memory with GFP_DMA even if that flag is unnecessary. We need to do cleanup later.

Thanks for reviewing and giving out some awesome suggestions.

Quoted 3 lines

Baoquan Are you planning to do it soon?
I want to help that.

Yes, I had the plan and have done a little part. I talked to Christoph about my thought. I planned to collect all kmalloc(GFP_DMA) callsite and post a RFC mail, CC mailing list and maintainers related. Anyone interested or know one or several callsites well can help.

Now, Christoph has handled all under drviers/scsi, and post patches to fix them. I have gone throug those places and found out below callsites where we can remove GFP_DMA directly when calling kmalloc() since not necessary. And even found one place kmalloc(GFP_DMA32).

(HEAD -> master) vxge: don't use GFP_DMA
mtd: rawnand: marvell: don't use GFP_DMA
HID: intel-ish-hid: remove wrong GFP_DMA32 flag
ps3disk: don't use GFP_DMA
atm: iphase: don't use GFP_DMA

Next, I will send a RFC mail to contain those suspect callsites. We can track them and can help if needed. Suggest to change them with:
1) using dma_alloc_xx , or dma_map_xx after kmalloc()
2) using alloc_pages(GFP_DMA) instead

When we fix, we all post patch with subject key words as 'xxxx: don't use GFP_DMA'. Christoph has posted patch with the similar subject, we can search subject to get all related patches for later back porting.

I will add you to CC when sending. Could be tomorrow. Any suggestion or thought?

Thanks
Baoquan

#11 lore raw

Re: [PATCH v4 3/3] mm/page_alloc.c: do not warn allocation failure on zone DMA if no managed pages

Quoted 20 lines · Baoquan He
Quoted 1 line · Hyeonggon Yoo

On Thu, Dec 23, 2021 at 05:44:35PM +0800, Baoquan He wrote:

......

Quoted 17 lines

mm/page_alloc.c void warn_alloc(gfp_t gfp_mask, nodemask_t *nodemask, const char *fmt, ...) · line 4210

Quoted 13 lines
mm/page_alloc.c +2 -1
index 7c7a0b5de2ff..843bc8e5550a 100644
@@ -4204,7 +4204,8 @@ void warn_alloc(gfp_t gfp_mask, nodemask_t *nodemask, const char *fmt, ...)
 	va_list args;
 	static DEFINE_RATELIMIT_STATE(nopage_rs, 10*HZ, 1);
 
-	if ((gfp_mask & __GFP_NOWARN) || !__ratelimit(&nopage_rs))
+	if ((gfp_mask & __GFP_NOWARN) || !__ratelimit(&nopage_rs) ||
+		(gfp_mask & __GFP_DMA) && !has_managed_dma())
 		return;
 

Warning when there's always no page in DMA zone is unnecessary and it confuses user.

Quoted 8 lines
Quoted 5 lines

The patch looks good.

And there is some driers that allocate memory with GFP_DMA even if that flag is unnecessary. We need to do cleanup later.

Thanks for reviewing and giving out some awesome suggestions.

You're welcome. Impressed to see you keep following the issue.

Quoted 9 lines
Quoted 3 lines

Baoquan Are you planning to do it soon?
I want to help that.

Yes, I had the plan and have done a little part. I talked to Christoph about my thought. I planned to collect all kmalloc(GFP_DMA) callsite and post a RFC mail, CC mailing list and maintainers related. Anyone interested or know one or several callsites well can help.

Good to hear that.
I want to help by reviewing and discussing your patches.

Quoted 2 lines

Now, Christoph has handled all under drviers/scsi, and post patches to fix them.

Oh, didn't know he was already doing that work.

Quoted 3 lines

I have gone throug those places and found out below callsites where we can remove GFP_DMA directly when calling kmalloc() since not necessary.

Note that some of them might have 24bit addressing limitation. we need to ask maintainer or read its specification to know GFP_DMA is unnecessary.

Quoted 1 line

And even found one place kmalloc(GFP_DMA32).

kmalloc(GFP_DMA32) is wrong because we do not create DMA32 kmalloc caches.

Quoted 10 lines

(HEAD -> master) vxge: don't use GFP_DMA
mtd: rawnand: marvell: don't use GFP_DMA
HID: intel-ish-hid: remove wrong GFP_DMA32 flag
ps3disk: don't use GFP_DMA
atm: iphase: don't use GFP_DMA

Next, I will send a RFC mail to contain those suspect callsites. We can track them and can help if needed. Suggest to change them with:
1) using dma_alloc_xx , or dma_map_xx after kmalloc()
2) using alloc_pages(GFP_DMA) instead

Well if the buffer is not sensitive to performance, we can just allocate with kmalloc(GFP_KERNEL) so that dma api can use proper bounce buffer.

if the buffer is for fastpath, I think we should convert them to use dma_alloc_pages() to get a proper buffer.

Note that most of devices are already calling dma_map_xx directly or indirectly (think about block layer for example) if they don't use deprecated virt_to_bus() or friends.

But if the device do not use DMA API at all, we have few choices. maybe convert them to use alloc_pages(GFP_DMA/GFP_DMA32) I guess?

Quoted 10 lines

When we fix, we all post patch with subject key words as 'xxxx: don't use GFP_DMA'. Christoph has posted patch with the similar subject, we can search subject to get all related patches for later back porting.

I will add you to CC when sending. Could be tomorrow. Any suggestion or thought?

Thanks
Baoquan

Thank you!
Hyeonggon

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

Tested-by John Donnelly on the v4 series
#12 lore raw
In reply to Baoquan He
Quoted 123 lines · Baoquan He

**Problem observed:
On x86_64, when crash is triggered and entering into kdump kernel, page allocation failure can always be seen.

---------------------------------
DMA: preallocated 128 KiB GFP_KERNEL pool for atomic allocations
swapper/0: page allocation failure: order:5, mode:0xcc1(GFP_KERNEL|GFP_DMA), nodemask=(null),cpuset=/,mems_allowed=0

  CPU: 0 PID: 1 Comm: swapper/0
  Call Trace:
   dump_stack+0x7f/0xa1
   warn_alloc.cold+0x72/0xd6
   ......
   __alloc_pages+0x24d/0x2c0
   ......
   dma_atomic_pool_init+0xdb/0x176
   do_one_initcall+0x67/0x320
   ? rcu_read_lock_sched_held+0x3f/0x80
   kernel_init_freeable+0x290/0x2dc
   ? rest_init+0x24f/0x24f
   kernel_init+0xa/0x111
   ret_from_fork+0x22/0x30
  Mem-Info:
  ------------------------------------

***Root cause:
In the current kernel, it assumes that DMA zone must have managed pages and try to request pages if CONFIG_ZONE_DMA is enabled. While this is not always true. E.g in kdump kernel of x86_64, only low 1M is presented and locked down at very early stage of boot, so that this low 1M won't be added into buddy allocator to become managed pages of DMA zone. This exception will always cause page allocation failure if page is requested from DMA zone.

***Investigation:
This failure happens since below commit merged into linus's tree.
1a6a9044b967 x86/setup: Remove CONFIG_X86_RESERVE_LOW and reservelow= options 23721c8e92f7 x86/crash: Remove crash_reserve_low_1M()
f1d4d47c5851 x86/setup: Always reserve the first 1M of RAM
7c321eb2b843 x86/kdump: Remove the backup region handling
6f599d84231f x86/kdump: Always reserve the low 1M when the crashkernel option is specified

Before them, on x86_64, the low 640K area will be reused by kdump kernel. So in kdump kernel, the content of low 640K area is copied into a backup region for dumping before jumping into kdump. Then except of those firmware reserved region in [0, 640K], the left area will be added into buddy allocator to become available managed pages of DMA zone.

However, after above commits applied, in kdump kernel of x86_64, the low 1M is reserved by memblock, but not released to buddy allocator. So any later page allocation requested from DMA zone will fail.

At the beginning, if crashkernel is reserved, the low 1M need be locked down because AMD SME encrypts memory making the old backup region mechanims impossible when switching into kdump kernel.

Later, it was also observed that there are BIOSes corrupting memory under 1M. To solve this, in commit f1d4d47c5851, the entire region of low 1M is always reserved after the real mode trampoline is allocated.

Besides, recently, Intel engineer mentioned their TDX (Trusted domain extensions) which is under development in kernel also needs to lock down the low 1M. So we can't simply revert above commits to fix the page allocation failure from DMA zone as someone suggested.

***Solution:
Currently, only DMA atomic pool and dma-kmalloc will initialize and request page allocation with GFP_DMA during bootup.

So only initializ DMA atomic pool when DMA zone has available managed pages, otherwise just skip the initialization.

For dma-kmalloc(), for the time being, let's mute the warning of allocation failure if requesting pages from DMA zone while no manged pages. Meanwhile, change code to use dma_alloc_xx/dma_map_xx API to replace kmalloc(GFP_DMA), or do not use GFP_DMA when calling kmalloc() if not necessary. Christoph is posting patches to fix those under drivers/scsi/. Finally, we can remove the need of dma-kmalloc() as people suggested.

Changelog:
v3->v4:
- Split the old v3 into two separate patchset. The first two clean up/improvement patches in v3 have been sent out in a independent patchset. The fixes patchs are adapted and sent in this patchset.
- Do not change dma-kmalloc(), mute the warning of allocation failure instead if it's requesting page from DMA zone which has no managed pages.

v2-Resend -> v3:
- Re-implement has_managed_dma() according to David's suggestion.
- Add Fixes tag and cc stable.

v2->v2 RESEND:
- John pinged to push the repost of this patchset. So fix one typo of suject of patch 3/5; Fix a building error caused by mix declaration in patch 5/5. Both of them are found by John from his testing.
- Rewrite cover letter to add more information.

v1->v2:
Change to check if managed DMA zone exists. If DMA zone has managed pages, go further to request page from DMA zone to initialize. Otherwise, just skip to initialize stuffs which need pages from DMA zone.

v3:
https://urldefense.com/v3/__https://lore.kernel.org/all/20211213122712.23805-1-bhe at redhat.com/T/*u__;Iw!!ACWV5N9M2RV99hQ!e1KjpVuZycBkxdeNxcsRUQ7MH92KQQk7FfCZs5tzEcBVusUiph0w9zpxOgKpS2Y0ecPm$

V2 RESEND post:
https://urldefense.com/v3/__https://lore.kernel.org/all/20211207030750.30824-1-bhe at redhat.com/T/*u__;Iw!!ACWV5N9M2RV99hQ!e1KjpVuZycBkxdeNxcsRUQ7MH92KQQk7FfCZs5tzEcBVusUiph0w9zpxOgKpSzZmH18k$

v2 post:
https://urldefense.com/v3/__https://lore.kernel.org/all/20210810094835.13402-1-bhe at redhat.com/T/*u__;Iw!!ACWV5N9M2RV99hQ!e1KjpVuZycBkxdeNxcsRUQ7MH92KQQk7FfCZs5tzEcBVusUiph0w9zpxOgKpS0Fbih0f$

v1 post:
https://urldefense.com/v3/__https://lore.kernel.org/all/20210624052010.5676-1-bhe at redhat.com/T/*u__;Iw!!ACWV5N9M2RV99hQ!e1KjpVuZycBkxdeNxcsRUQ7MH92KQQk7FfCZs5tzEcBVusUiph0w9zpxOgKpSwc3nQBz$

Baoquan He (3):
mm_zone: add function to check if managed dma zone exists dma/pool: create dma atomic pool only if dma zone has managed pages mm/page_alloc.c: do not warn allocation failure on zone DMA if no
managed pages

Quoted 5 lines
  include/linux/mmzone.h |  9 +++++++++
  kernel/dma/pool.c      |  4 ++--
  mm/page_alloc.c        | 18 +++++++++++++++++-
  3 files changed, 28 insertions(+), 3 deletions(-)
Tested-by John Donnelly

I don't see GFP malloc failures when the CD-ROM is enumerated anymore either when kdump kernel is started.

tested on 5.15.13.