Re: kswapd0: page allocation failure: order:0, mode:0x820(GFP_ATOMIC), nodemask=(null),cpuset=/,mems_allowed=0 (Kernel v6.5.9, 32bit ppc)

Yosry Ahmed
2024-06-05T03:04:07Z

[-- Attachment #1: Type: text/plain, Size: 1196 bytes --]

On Tue, Jun 4, 2024 at 2:10 PM Erhard Furtner <erhard_f@mailbox.org> wrote:
>
> On Tue, 4 Jun 2024 11:01:39 -0700
> Yosry Ahmed <yosryahmed@google.com> wrote:
>
> > How many CPUs does this machine have? I am wondering if 32 can be an
> > overkill for small machines, perhaps the number of pools should be
> > max(nr_cpus, 32)?
>
> This PowerMac G4 DP got 2 CPUs. Not much for a desktop machine by todays standards but some SoCs have less. ;)
>
> # lscpu
> Architecture: ppc
> CPU op-mode(s): 32-bit
> Byte Order: Big Endian
> CPU(s): 2
> On-line CPU(s) list: 0,1
> Model name: 7455, altivec supported
> Model: 3.3 (pvr 8001 0303)
> Thread(s) per core: 1
> Core(s) per socket: 1
> Socket(s): 2
> BogoMIPS: 83.78
> Caches (sum of all):
> L1d: 64 KiB (2 instances)
> L1i: 64 KiB (2 instances)
> L2: 512 KiB (2 instances)
> L3: 4 MiB (2 instances)
>
> Regards,
> Erhard

Could you check if the attached patch helps? It basically changes the
number of zpools from 32 to min(32, nr_cpus).

[-- Attachment #2: 0001-mm-zswap-do-not-scale-the-number-of-zpools-unnecessa.patch --]
[-- Type: application/octet-stream, Size: 3935 bytes --]

From eb2baf6f3497936ec56fe17e22af5b5add624371 Mon Sep 17 00:00:00 2001
From: Yosry Ahmed <yosryahmed@google.com>
Date: Wed, 5 Jun 2024 02:58:11 +0000
Subject: [PATCH] mm: zswap: do not scale the number of zpools unnecessarily

Zswap allocates several zpools per zswap pool for scalability. It
currently allocates 32 zpools, an empirically determined magic number.

For small machines that has less than 32 CPUs, this doesn't make much
sense. Allocating more zpools than CPUs will not significantly increase
scalability, but it may increase internal fragmentation due to spreading
of compressed pages among different zpools.

determined at boot as the smaller of 32 and the number of CPUs.

Signed-off-by: Yosry Ahmed <yosryahmed@google.com>
---
mm/zswap.c | 35 ++++++++++++++++++++++++++---------
1 file changed, 26 insertions(+), 9 deletions(-)

diff --git a/mm/zswap.c b/mm/zswap.c
index a50e2986cd2fa..9c4a6d309b23c 100644
--- a/mm/zswap.c
+++ b/mm/zswap.c
@@ -123,8 +123,8 @@ static unsigned int zswap_accept_thr_percent = 90; /* of max pool size */
module_param_named(accept_threshold_percent, zswap_accept_thr_percent,
uint, 0644);

-/* Number of zpools in zswap_pool (empirically determined for scalability) */
-#define ZSWAP_NR_ZPOOLS 32
+/* Number of zpools in zswap_pool */
+static unsigned int nr_zswap_zpools __ro_after_init;

/* Enable/disable memory pressure-based shrinker. */
static bool zswap_shrinker_enabled = IS_ENABLED(
@@ -156,7 +156,7 @@ struct crypto_acomp_ctx {
* needs to be verified that it's still valid in the tree.
*/
struct zswap_pool {
- struct zpool *zpools[ZSWAP_NR_ZPOOLS];
+ struct zpool **zpools;
struct crypto_acomp_ctx __percpu *acomp_ctx;
struct percpu_ref ref;
struct list_head list;
@@ -268,7 +268,14 @@ static struct zswap_pool *zswap_pool_create(char *type, char *compressor)
if (!pool)
return NULL;

- for (i = 0; i < ZSWAP_NR_ZPOOLS; i++) {
+ pool->zpools = kcalloc(nr_zswap_zpools, sizeof(pool->zpools[0]),
+ GFP_KERNEL);
+ if (!pool->zpools) {
+ pr_err("zpools alloc failed\n");
+ goto error;
+ }
+
+ for (i = 0; i < nr_zswap_zpools; i++) {
/* unique name for each pool specifically required by zsmalloc */
snprintf(name, 38, "zswap%x",
atomic_inc_return(&zswap_pools_count));
@@ -312,8 +319,11 @@ static struct zswap_pool *zswap_pool_create(char *type, char *compressor)
error:
if (pool->acomp_ctx)
free_percpu(pool->acomp_ctx);
- while (i--)
- zpool_destroy_pool(pool->zpools[i]);
+ if (pool->zpools) {
+ while (i--)
+ zpool_destroy_pool(pool->zpools[i]);
+ kfree(pool->zpools);
+ }
kfree(pool);
return NULL;
}
@@ -369,8 +379,9 @@ static void zswap_pool_destroy(struct zswap_pool *pool)
cpuhp_state_remove_instance(CPUHP_MM_ZSWP_POOL_PREPARE, &pool->node);
free_percpu(pool->acomp_ctx);

- for (i = 0; i < ZSWAP_NR_ZPOOLS; i++)
+ for (i = 0; i < nr_zswap_zpools; i++)
zpool_destroy_pool(pool->zpools[i]);
+ kfree(pool->zpools);
kfree(pool);
}

@@ -496,7 +507,7 @@ unsigned long zswap_total_pages(void)
list_for_each_entry_rcu(pool, &zswap_pools, list) {
int i;

- for (i = 0; i < ZSWAP_NR_ZPOOLS; i++)
+ for (i = 0; i < nr_zswap_zpools; i++)
total += zpool_get_total_pages(pool->zpools[i]);
}
rcu_read_unlock();
@@ -805,7 +816,7 @@ static void zswap_entry_cache_free(struct zswap_entry *entry)

static struct zpool *zswap_find_zpool(struct zswap_entry *entry)
{
- return entry->pool->zpools[hash_ptr(entry, ilog2(ZSWAP_NR_ZPOOLS))];
+ return entry->pool->zpools[hash_ptr(entry, ilog2(nr_zswap_zpools))];
}

/*
@@ -1767,6 +1778,12 @@ static int zswap_setup(void)

static int __init zswap_init(void)
{
+ /*
+ * Use multiple zpools for scalability, but avoid allocating too many.
+ * 32 is an empirically determined magic number.
+ */
+ nr_zswap_zpools = min(32U, num_possible_cpus());
+
if (!zswap_enabled)
return 0;
return zswap_setup();
--
2.45.1.288.g0e0cd299f1-goog