From nobody Mon Feb 9 04:31:17 2026 Received: from mail-pl1-f178.google.com (mail-pl1-f178.google.com [209.85.214.178]) (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 9C40A3218B3 for ; Sat, 17 Jan 2026 02:54:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.178 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768618462; cv=none; b=N2mWCTYge441fK4Flks9xkrzatw05OgB2TTOFoKaBVD7usfjvOQDmj8FPQXdl7aYYE2x+/PFXfnJSa0kQ50ZnerE2m+y30CewXAuuaxshHvfvalyHl0FLcj/Au8E8194S2xPNTHfm7QWUGq/F8ltWb1kib6Jo7WZ+PTZ0eGk89o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768618462; c=relaxed/simple; bh=TadWN8vu82K1MLpbxHlpBtCdduLc+2/VWCZvr5L170A=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=DkW4VThp3tCZI73o4NsriLPf9aC+PXTmLXCchNjCpwvXt3X4AiH3ZqGTE1F3MCO5w/eRDAF/iltn2cMFwZ41zBJfCgTWBfu/AqNCdbvIa3+2zqmrQa5qMXdJUxuBR1+l+YL5zez0yny5dIl3Kl+Qf05SpSpolWzxGJxJHXJ8Pk4= 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=RvG8bUAq; arc=none smtp.client-ip=209.85.214.178 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="RvG8bUAq" Received: by mail-pl1-f178.google.com with SMTP id d9443c01a7336-2a0ac29fca1so16901605ad.2 for ; Fri, 16 Jan 2026 18:54:20 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1768618460; x=1769223260; 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=7zbu0DneLCA70t4hlen3zQtX7oTzsmiELCeInRa1oIY=; b=RvG8bUAqxUKf+dpSZQCXujU1lmZz9KX00bWzd+7Zuj6EZQWmkORDz+5UANVyJp5p9I jZCVk6ZnAtz5OQ32SD5pd86RjhvE6G4PBvq4Z9rQ3my7U2H/M7dxY5rDXw9RIckAQ216 7iyvtvDtJoaIRlLtgHN+PUgYcVkX6yCbEutUo= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1768618460; x=1769223260; 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=7zbu0DneLCA70t4hlen3zQtX7oTzsmiELCeInRa1oIY=; b=scXMRL0vcoOicL1+uBRkdrVAMSrDFFWwIK7/DnJ1DEESpEhtENjdTrhbzrQDDjUIQV fb4YMpybDex1N66RVNlKX7Un5PaLhUlxX/ueUKooMG1PuqrhBMdJdj8dJiDT4b25nie3 ydPKu3LfRDdSLYCmUlfgEv8+3kVO3bqOutiBnmvrLT6rTA9w2VwWO8xjMSFhDJJd8isw UZ0dUSd0brHrCz1ouRM2Dy02VtTffp6O9RMYxY4tMj9PU80NvpUeHC9Difdd6TGjcp5W Eeur0GQ2fJgRDCC8RIX6ZeoTQ+6OnvEmxN4BlMVHhuA51B/YrsBnby5ATLVW626fChYU N+sg== X-Forwarded-Encrypted: i=1; AJvYcCUYGlI6YE2n4e8Jb52PTwIGHzVqiY+h5OfpVXOHNP2g3xCxx5ZNpzhMavJKxK231bKrWl/LNiXwXbvbPCo=@vger.kernel.org X-Gm-Message-State: AOJu0Ywb4eipWUxLnwG9A5Ssnjijdg54wHCerhrbo+qET5FWIkF4NqAz kNNOZSpY3BKf9ZqlbMYET16bQiVw1Sd1UzkdjtI9R8uhTcpp0P7axICUsPgK2Hl4Dw== X-Gm-Gg: AY/fxX4sWbsNoScBRANkMPuHvM+XMe5k6PAA0xx47treA1cbbc1bROBSPEdJuh58BE4 AC9sqLEo0WQqF9/tbJ61fkVCOjnzz/+TBdw/g/GORgsz0gHACt25UD2HVkiuFXoHOzABDdoo4Y6 flnTCxRFe0cDK9GuRJqhGjcpFkgE3xe45X6sksRkqxVrTvEfrRkateCQvnJZ7R/j7hWMApiwBwx QW1GHt338CRlranB/pfxfqUjaiWZxLeTsxSRQChuRxrYLj6GsTIwdgB2GguSCA+O10/nVlskMgr suwSyxPTz60cE2UdSQvn91rU2t8R+mWqKzlYAIsPSWPPve+gVN+/o6w5lqub/ZtwFLLQgXu44jp xGWt05gRr6Dg/skRS4iAIEh7adZfzGQVGdmaIHTZWNvebnTdmQlJh+k3H/fjns+iEJjvzC1cgGg aEbf4MBQsiWSfMxUTmHY6Q4LfOKcLk+ayqW4D7kGywgZdwZPZh9CsNlz8MVU6ra4lV6m20II5/l Q== X-Received: by 2002:a17:902:e949:b0:299:e031:173 with SMTP id d9443c01a7336-2a7175a639amr47201055ad.35.1768618459805; Fri, 16 Jan 2026 18:54:19 -0800 (PST) Received: from tigerii.tok.corp.google.com ([2a00:79e0:2031:6:fb0f:ccef:d815:5581]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2a7193fbf76sm32252665ad.71.2026.01.16.18.54.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 16 Jan 2026 18:54:19 -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: [PATCHv2] zsmalloc: make common caches global Date: Sat, 17 Jan 2026 11:54:05 +0900 Message-ID: <20260117025406.799428-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. The memory savings depend on particular setup and data patterns and can be found via slabinfo. Signed-off-by: Sergey Senozhatsky Reviewed-by: Nhat Pham Reviewed-by: Yosry Ahmed --- v1->v2: - factored out zs_destroy_caches/zs_init_caches (Yosry) mm/zsmalloc.c | 106 ++++++++++++++++++++++++-------------------------- 1 file changed, 50 insertions(+), 56 deletions(-) diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index 5a68349403d5..8df45aa1b5c8 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; - } + gfp =3D gfp & ~(__GFP_HIGHMEM | __GFP_MOVABLE); =20 - return 0; -} - -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); @@ -1344,7 +1313,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 @@ -1368,7 +1337,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 @@ -1448,7 +1417,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 @@ -2110,9 +2079,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. @@ -2234,20 +2200,47 @@ void zs_destroy_pool(struct zs_pool *pool) kfree(class); } =20 - destroy_cache(pool); kfree(pool->name); kfree(pool); } EXPORT_SYMBOL_GPL(zs_destroy_pool); =20 +static void zs_destroy_caches(void) +{ + kmem_cache_destroy(handle_cachep); + handle_cachep =3D NULL; + kmem_cache_destroy(zspage_cachep); + zspage_cachep =3D NULL; +} + +static int __init zs_init_caches(void) +{ + handle_cachep =3D kmem_cache_create("zs_handle", ZS_HANDLE_SIZE, + 0, 0, NULL); + zspage_cachep =3D kmem_cache_create("zspage", sizeof(struct zspage), + 0, 0, NULL); + + if (!handle_cachep || !zspage_cachep) { + zs_destroy_caches(); + return -ENOMEM; + } + return 0; +} + static int __init zs_init(void) { - int rc __maybe_unused; + int rc; + + rc =3D zs_init_caches(); + if (rc) + return rc; =20 #ifdef CONFIG_COMPACTION rc =3D set_movable_ops(&zsmalloc_mops, PGTY_zsmalloc); - if (rc) + if (rc) { + zs_destroy_caches(); return rc; + } #endif zs_stat_init(); return 0; @@ -2259,6 +2252,7 @@ static void __exit zs_exit(void) set_movable_ops(NULL, PGTY_zsmalloc); #endif zs_stat_exit(); + zs_destroy_caches(); } =20 module_init(zs_init); --=20 2.52.0.457.g6b5491de43-goog