From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A91432517AF for ; Tue, 11 Aug 2026 00:20:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786407605; cv=none; b=ExlMTOvBgOnh6L9YXjl1JuDrRPfgil0PZBwGfJwj8buJFBKXbtUboEfo20lTMr6Po5VlrImMawh1xoOJDybkoxNDxwYIce8v7ZBGjQpgBz6R3WYvYxNTv9eOB+7nK1XD1O7BhoezxlTAMAhrvNfPZ3m6bGlw0guMtp3ikGbVCsY= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786407605; c=relaxed/simple; bh=/VYfuGcKbgS+0ttqxo8eXahiJh1kGeC8NiUe0iU5rTk=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=hU+D9/S/fVN+9QAvv7EG7GwUmks0f401rqIkBGmohOW0oxIxMP9anLQKIJV/6P31FmlEe9tWpm5MfqrHEjgVeGafSDHDvMV5bHbRc4uPerOqksPvpDXkdihb26bggSW82X2QUj7sAmrIqDu57A14NP94+yJfVtYuK2zDWdKV5nM= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=MsvQaDP1; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="MsvQaDP1" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E076F1F00A3D; Tue, 11 Aug 2026 00:20:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1786407604; bh=cryaumeVoeRHiTcn7Qll1wUbNn7JyWDDqdD+Hq0Hrec=; h=Date:From:To:Cc:Subject:References:In-Reply-To; b=MsvQaDP1RTtw8rHYgfjJUO/5UXJUveGiJDdFR7VhgB5+Y/GSwdqMxNqS3jnj4aD6y 5lYfDWchuwApdcE1z8Yl3FSB2xoIK8tprYuEGXj14Po8zF9eHtdNPoomWftT7hKlEi ZWZP81lMM/CNkkyklotI3LlpqeqsqZgtT/PvPFYi+bF+mGGdQtg0J6I2qbLUG+PAre s3aVoiRxeETlyLs0mGL8i867UMSSBW+klgiCbseFJ1r1fOZn1Qc5rgpVdqrR71+Glu KaIJRjSYCOb5BFO8m9mRq9v9TLZJ2aOS4BQB7moZj0m9iGZQEt1rpbHPHAKr80zDmQ uqf2bcCMWICEg== Date: Tue, 11 Aug 2026 00:20:02 +0000 From: Yosry Ahmed To: Jianyue Wu Cc: linux-mm@kvack.org, linux-kernel@vger.kernel.org, Johannes Weiner , Nhat Pham , Chengming Zhou , Andrew Morton , Chris Li Subject: Re: [PATCH RFC v2 2/2] mm/zswap: reference the pool by index to shrink struct zswap_entry Message-ID: References: <20260731-shrink_zswap_entry_v2-0-0-v2-0-e72083aa8734@gmail.com> <20260731-shrink_zswap_entry_v2-0-0-v2-2-e72083aa8734@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20260731-shrink_zswap_entry_v2-0-0-v2-2-e72083aa8734@gmail.com> On Fri, Jul 31, 2026 at 08:32:48AM +0800, Jianyue Wu wrote: > struct zswap_entry is one allocation per stored page, so its size is pure > overhead. It currently embeds an 8-byte pool pointer, even though the > live pools now sit in a small fixed array indexed by a u8 slot number. > > Replace the per-entry pool pointer with that u8 slot index and resolve it > through a zswap_entry_pool() helper. A live entry holds a reference to > its pool, so the slot cannot be reused under it; the lookup therefore > needs no RCU read-side section (rcu_dereference_protected(..., true)). > > The u8 fits in the padding after the bool referenced field, shrinking the > entry from 56 to 48 bytes on x86_64. This raises objs_per_slab from 73 > to 85 and saves about 2MiB of metadata per 1GiB of data held in zswap. > > Suggested-by: Chris Li > Signed-off-by: Jianyue Wu > --- > mm/zswap.c | 33 +++++++++++++++++++++++++-------- > 1 file changed, 25 insertions(+), 8 deletions(-) > > diff --git a/mm/zswap.c b/mm/zswap.c > index b203934d3be8..d4f4db2999f2 100644 > --- a/mm/zswap.c > +++ b/mm/zswap.c > @@ -190,7 +190,7 @@ static struct shrinker *zswap_shrinker; > * writeback logic. The entry is only reclaimed by the writeback > * logic if referenced is unset. See comments in the shrinker > * section for context. > - * pool - the zswap_pool the entry's data is in > + * pool_idx - slot of the zswap_pool that the entry's data is in. > * handle - zsmalloc allocation handle that stores the compressed page data > * objcg - the obj_cgroup that the compressed memory is charged to > * lru - handle to the pool's lru used to evict pages. > @@ -199,12 +199,22 @@ struct zswap_entry { > swp_entry_t swpentry; > unsigned int length; > bool referenced; > - struct zswap_pool *pool; > + u8 pool_idx; > unsigned long handle; > struct obj_cgroup *objcg; > struct list_head lru; > }; > > +static struct zswap_pool *zswap_entry_pool(struct zswap_entry *entry) > +{ > + /* > + * A live entry holds a reference to its pool, so the slot cannot be > + * cleared or reused under it. This is not an RCU read-side walk. > + */ > + return rcu_dereference_protected(zswap_pools[entry->pool_idx], > + true /* entry pins pool */); Probably doesn't matter in practice, but maybe entry->handle or something instead of 'true' to make it clear we are checking for an "active" entry? > +} > + > static struct xarray *zswap_trees[MAX_SWAPFILES]; > static unsigned int nr_zswap_trees[MAX_SWAPFILES]; > > @@ -807,9 +817,13 @@ static void zswap_entry_cache_free(struct zswap_entry *entry) > */ > static void zswap_entry_free(struct zswap_entry *entry) > { > + struct zswap_pool *pool = zswap_entry_pool(entry); > + > zswap_lru_del(&zswap_list_lru, entry); > - zs_free(entry->pool->zs_pool, entry->handle); > - zswap_pool_put(entry->pool); > + if (!WARN_ON_ONCE(!pool)) { > + zs_free(pool->zs_pool, entry->handle); > + zswap_pool_put(pool); > + } > if (entry->objcg) { > obj_cgroup_uncharge_zswap(entry->objcg, entry->length); > obj_cgroup_put(entry->objcg); > @@ -966,12 +980,15 @@ static bool zswap_compress(struct page *page, struct zswap_entry *entry, > > static bool zswap_decompress(struct zswap_entry *entry, struct folio *folio) > { > - struct zswap_pool *pool = entry->pool; > + struct zswap_pool *pool = zswap_entry_pool(entry); > struct scatterlist input[2]; /* zsmalloc returns an SG list 1-2 entries */ > struct scatterlist output; > struct crypto_acomp_ctx *acomp_ctx; > int ret = 0, dlen; > > + if (WARN_ON_ONCE(!pool)) > + return false; > + > acomp_ctx = raw_cpu_ptr(pool->acomp_ctx); > mutex_lock(&acomp_ctx->mutex); > zs_obj_read_sg_begin(pool->zs_pool, entry->handle, input, entry->length); > @@ -1007,7 +1024,7 @@ static bool zswap_decompress(struct zswap_entry *entry, struct folio *folio) > pr_alert_ratelimited("Decompression error from zswap (%d:%lu %s %u->%d)\n", > swp_type(entry->swpentry), > swp_offset(entry->swpentry), > - entry->pool->tfm_name, > + pool->tfm_name, > entry->length, dlen); > return false; > } > @@ -1500,7 +1517,7 @@ static bool zswap_store_page(struct page *page, > * The publishing order matters to prevent writeback from seeing > * an incoherent entry. > */ > - entry->pool = pool; > + entry->pool_idx = pool->idx; > entry->swpentry = page_swpentry; > entry->objcg = objcg; > entry->referenced = true; > @@ -1806,7 +1823,7 @@ static int zswap_setup(void) > struct zswap_pool *pool; > int ret; > > - /* Slot indices are stored in a u8 (pool->idx). */ > + /* Slot indices are stored in a u8 (pool->idx and entry->pool_idx). */ > BUILD_BUG_ON(ZSWAP_MAX_POOLS - 1 > U8_MAX); > > zswap_entry_cache = KMEM_CACHE(zswap_entry, 0); > > -- > 2.43.0 >