From nobody Mon Feb 9 09:18:13 2026 Received: from mail-pf1-f180.google.com (mail-pf1-f180.google.com [209.85.210.180]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C954113B284 for ; Fri, 16 Jan 2026 04:49:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.180 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768538954; cv=none; b=ny54cNPCSkDzbIJsHCy5bW7BpsjXhKN7JJ9ipAvXV1P/6Byr8p6ANrv4S56jVIiVyE7rQpZIqo28SjBiv5ESN+u1XR0zu8xlN8BjQ2TxpwwMyYOCSw7/wcWfyqNb4AzWt0Tlx5VPAJAazsjLGmfyhDcJWFLgnaxU+mIJBVEQXoM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768538954; c=relaxed/simple; bh=kU6A+a0ngfx5fAORTRXZs+UKQibecS7iRODR5BnnSZQ=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=t78Vm4wzl8Ybhi10zWiWBdLzhRWp/a8FpAOkVCA+QLl/P19n26W2VXzazEKjAp6TjBz/33iIavum+cZwvXnzXV7MtaIZCEIDLum2P5BUwxveej9Vfwa9scXgnP2UrtxM8nuEKyfPwdmp/Pk0DG2xlZ4Z8gsVAtvjlahe5Xkyvz4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=chromium.org; spf=pass smtp.mailfrom=chromium.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b=aNNPlUoh; arc=none smtp.client-ip=209.85.210.180 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=chromium.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="aNNPlUoh" Received: by mail-pf1-f180.google.com with SMTP id d2e1a72fcca58-81dbc0a99d2so834618b3a.1 for ; Thu, 15 Jan 2026 20:49:08 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1768538945; x=1769143745; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=xzwKGJFEXzcfmx1MjYg5YriTA/MrKdzyh60azwxmvPA=; b=aNNPlUohy8Rwp16UQm7+RRCX+6tRvCp9Oy7fjrFJXO3dNuRdkDxgGUFBmZeAof3I6g n3mWvRUydNszhQhDhLnlbO+XgyVYIEVL+rIUVRtxTbfenW2N6ENuWag6kH2f6UgvKV96 10Cig+auPSXD/Gm9b3OJ9yApQS5FTgCFNIbG8= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1768538945; x=1769143745; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=xzwKGJFEXzcfmx1MjYg5YriTA/MrKdzyh60azwxmvPA=; b=vpgsc+KpN/S47LED/ECNxENpR+qLLP78ufcT4g63DMNvVmBMFgsQFd296EGALp578K cDvy97wxj/frmwrxuKeOUT1fZwXmDkbMygzTobS5giPlPQqoH/qXqK2LHQLpJRi2aclG Fd9S0rWahtPQB/OFOJHKvylIefsZmWnjYTnMGH8dWLucmzRnTRvG04eCq9QzgtOocqNJ dbUcybtbubtiS+Pjep/PMSgWhNul0si2NZgCfHARE6QB59LbSlfWRi1yVS5udeR8L6OX fGZy8abMAN4t7okdeGC/KlpLefycmFAsz7i88bxzQ0OOid/1+HUtVGlm0zL1VruMYZb7 tLAw== X-Forwarded-Encrypted: i=1; AJvYcCUCslIgMrlwHVKAmZsY6wdWrtQ8o++VN0JyEbim56HcEa9iWRuzcg5ocGB9E0ceFZ3yD2Sq1uweB9ENsJo=@vger.kernel.org X-Gm-Message-State: AOJu0YyOC+yPva917EGZs4WXxAWll5D5AZNJ1oVXww+Q5qF3Xu62HJ/b QWbETdansU4eRegBSzS0iqU4g8/dONGfUF+sXeCntmsvRo9RUC6qC/Umpe+tv59oUg== X-Gm-Gg: AY/fxX7Nd/0PgYUvkmQ++eVNbOu1LlzU0etehM14oNJbMdHxD5j0tdlZIbTfX0lhjB8 tH5uYmUfQbcc2n32jXJS4eR1OITQlBOZRwKPvSdJ7ZeNymlPGLsjU1axuHpQtarZ66EgCEwybcZ z2Rs8djzJSJYW1yPOvKxfiLu1Whz8uPLdRV+KNzmNlpifd+6GvNwl8ZWCKADw2QAax+Ezyv3/IO hlkb0vM042tN6yZXfo8fpZmVd92sVDmOLpQsG3K0FnwCuY0g81PttZ12ebL4ncnP4GJpFjcb/rc zeB24NSXKDx0GoiVbEIp/+8nda0FKpcpomMmimuhdTh7n7byc2F3XgwpjLaKk/Yk8LHzpJtLsjI O11f5Fr9rXPSm7owWabhFI/QQjPN7cj0zdeTw6h4NugUjWqclcYjas71EMPPAd5JCL524mK1WNF +yQULCX7RTkVHYjwpJIkZZKqX+6G7QlwaqVDg8ND4KsCLGMVNZYW4GxaxznPBnuPYALzqS25A= X-Received: by 2002:a05:6a00:1a8e:b0:81f:4884:4fed with SMTP id d2e1a72fcca58-81f9f7e4789mr1785267b3a.7.1768538944715; Thu, 15 Jan 2026 20:49:04 -0800 (PST) Received: from tigerii.tok.corp.google.com ([2a00:79e0:2031:6:ba7a:360:116f:dac]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-81fa1291135sm820852b3a.47.2026.01.15.20.49.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 15 Jan 2026 20:49:04 -0800 (PST) From: Sergey Senozhatsky To: Andrew Morton , Yosry Ahmed Cc: Minchan Kim , Nhat Pham , Johannes Weiner , Brian Geffon , linux-kernel@vger.kernel.org, linux-mm@kvack.org, Sergey Senozhatsky Subject: [RFC PATCH] zsmalloc: make common caches global Date: Fri, 16 Jan 2026 13:48:41 +0900 Message-ID: <20260116044841.334821-1-senozhatsky@chromium.org> X-Mailer: git-send-email 2.52.0.457.g6b5491de43-goog Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Currently, zsmalloc creates kmem_cache of handles and zspages for each pool, which may be suboptimal from the memory usage point of view (extra internal fragmentation per pool). Systems that create multiple zsmalloc pools may benefit from shared common zsmalloc caches. Make handles and zspages kmem caches global. Signed-off-by: Sergey Senozhatsky --- mm/zsmalloc.c | 95 ++++++++++++++++++++++----------------------------- 1 file changed, 40 insertions(+), 55 deletions(-) diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index 5abb8bc0956a..05ed3539aa1e 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -198,12 +198,13 @@ struct link_free { }; }; =20 +static struct kmem_cache *handle_cachep; +static struct kmem_cache *zspage_cachep; + struct zs_pool { const char *name; =20 struct size_class *size_class[ZS_SIZE_CLASSES]; - struct kmem_cache *handle_cachep; - struct kmem_cache *zspage_cachep; =20 atomic_long_t pages_allocated; =20 @@ -376,60 +377,28 @@ static void init_deferred_free(struct zs_pool *pool) = {} static void SetZsPageMovable(struct zs_pool *pool, struct zspage *zspage) = {} #endif =20 -static int create_cache(struct zs_pool *pool) +static unsigned long cache_alloc_handle(gfp_t gfp) { - char *name; - - name =3D kasprintf(GFP_KERNEL, "zs_handle-%s", pool->name); - if (!name) - return -ENOMEM; - pool->handle_cachep =3D kmem_cache_create(name, ZS_HANDLE_SIZE, - 0, 0, NULL); - kfree(name); - if (!pool->handle_cachep) - return -EINVAL; - - name =3D kasprintf(GFP_KERNEL, "zspage-%s", pool->name); - if (!name) - return -ENOMEM; - pool->zspage_cachep =3D kmem_cache_create(name, sizeof(struct zspage), - 0, 0, NULL); - kfree(name); - if (!pool->zspage_cachep) { - kmem_cache_destroy(pool->handle_cachep); - pool->handle_cachep =3D NULL; - return -EINVAL; - } - - return 0; -} + gfp =3D gfp & ~(__GFP_HIGHMEM | __GFP_MOVABLE); =20 -static void destroy_cache(struct zs_pool *pool) -{ - kmem_cache_destroy(pool->handle_cachep); - kmem_cache_destroy(pool->zspage_cachep); + return (unsigned long)kmem_cache_alloc(handle_cachep, gfp); } =20 -static unsigned long cache_alloc_handle(struct zs_pool *pool, gfp_t gfp) +static void cache_free_handle(unsigned long handle) { - return (unsigned long)kmem_cache_alloc(pool->handle_cachep, - gfp & ~(__GFP_HIGHMEM|__GFP_MOVABLE)); + kmem_cache_free(handle_cachep, (void *)handle); } =20 -static void cache_free_handle(struct zs_pool *pool, unsigned long handle) +static struct zspage *cache_alloc_zspage(gfp_t gfp) { - kmem_cache_free(pool->handle_cachep, (void *)handle); -} + gfp =3D gfp & ~(__GFP_HIGHMEM | __GFP_MOVABLE); =20 -static struct zspage *cache_alloc_zspage(struct zs_pool *pool, gfp_t flags) -{ - return kmem_cache_zalloc(pool->zspage_cachep, - flags & ~(__GFP_HIGHMEM|__GFP_MOVABLE)); + return kmem_cache_zalloc(zspage_cachep, gfp); } =20 -static void cache_free_zspage(struct zs_pool *pool, struct zspage *zspage) +static void cache_free_zspage(struct zspage *zspage) { - kmem_cache_free(pool->zspage_cachep, zspage); + kmem_cache_free(zspage_cachep, zspage); } =20 /* class->lock(which owns the handle) synchronizes races */ @@ -858,7 +827,7 @@ static void __free_zspage(struct zs_pool *pool, struct = size_class *class, zpdesc =3D next; } while (zpdesc !=3D NULL); =20 - cache_free_zspage(pool, zspage); + cache_free_zspage(zspage); =20 class_stat_sub(class, ZS_OBJS_ALLOCATED, class->objs_per_zspage); atomic_long_sub(class->pages_per_zspage, &pool->pages_allocated); @@ -971,7 +940,7 @@ static struct zspage *alloc_zspage(struct zs_pool *pool, { int i; struct zpdesc *zpdescs[ZS_MAX_PAGES_PER_ZSPAGE]; - struct zspage *zspage =3D cache_alloc_zspage(pool, gfp); + struct zspage *zspage =3D cache_alloc_zspage(gfp); =20 if (!zspage) return NULL; @@ -993,7 +962,7 @@ static struct zspage *alloc_zspage(struct zs_pool *pool, zpdesc_dec_zone_page_state(zpdescs[i]); free_zpdesc(zpdescs[i]); } - cache_free_zspage(pool, zspage); + cache_free_zspage(zspage); return NULL; } __zpdesc_set_zsmalloc(zpdesc); @@ -1346,7 +1315,7 @@ unsigned long zs_malloc(struct zs_pool *pool, size_t = size, gfp_t gfp, if (unlikely(size > ZS_MAX_ALLOC_SIZE)) return (unsigned long)ERR_PTR(-ENOSPC); =20 - handle =3D cache_alloc_handle(pool, gfp); + handle =3D cache_alloc_handle(gfp); if (!handle) return (unsigned long)ERR_PTR(-ENOMEM); =20 @@ -1370,7 +1339,7 @@ unsigned long zs_malloc(struct zs_pool *pool, size_t = size, gfp_t gfp, =20 zspage =3D alloc_zspage(pool, class, gfp, nid); if (!zspage) { - cache_free_handle(pool, handle); + cache_free_handle(handle); return (unsigned long)ERR_PTR(-ENOMEM); } =20 @@ -1450,7 +1419,7 @@ void zs_free(struct zs_pool *pool, unsigned long hand= le) free_zspage(pool, class, zspage); =20 spin_unlock(&class->lock); - cache_free_handle(pool, handle); + cache_free_handle(handle); } EXPORT_SYMBOL_GPL(zs_free); =20 @@ -2112,9 +2081,6 @@ struct zs_pool *zs_create_pool(const char *name) if (!pool->name) goto err; =20 - if (create_cache(pool)) - goto err; - /* * Iterate reversely, because, size of size_class that we want to use * for merging should be larger or equal to current size. @@ -2236,7 +2202,6 @@ void zs_destroy_pool(struct zs_pool *pool) kfree(class); } =20 - destroy_cache(pool); kfree(pool->name); kfree(pool); } @@ -2246,10 +2211,28 @@ static int __init zs_init(void) { int rc __maybe_unused; =20 + handle_cachep =3D kmem_cache_create("zs_handle", ZS_HANDLE_SIZE, 0, 0, + NULL); + if (!handle_cachep) + return -ENOMEM; + + zspage_cachep =3D kmem_cache_create("zspage", sizeof(struct zspage), 0, + 0, NULL); + if (!zspage_cachep) { + kmem_cache_destroy(handle_cachep); + handle_cachep =3D NULL; + return -ENOMEM; + } + #ifdef CONFIG_COMPACTION rc =3D set_movable_ops(&zsmalloc_mops, PGTY_zsmalloc); - if (rc) + if (rc) { + kmem_cache_destroy(zspage_cachep); + kmem_cache_destroy(handle_cachep); + zspage_cachep =3D NULL; + handle_cachep =3D NULL; return rc; + } #endif zs_stat_init(); return 0; @@ -2261,6 +2244,8 @@ static void __exit zs_exit(void) set_movable_ops(NULL, PGTY_zsmalloc); #endif zs_stat_exit(); + kmem_cache_destroy(zspage_cachep); + kmem_cache_destroy(handle_cachep); } =20 module_init(zs_init); --=20 2.52.0.457.g6b5491de43-goog