Re: [PATCH RFC v3 3/3] mm/zswap: reference the pool by index to shrink struct zswap_entry

From: Yosry Ahmed

Date: Tue Aug 25 2026 - 13:17:16 EST


On Fri, Aug 14, 2026 at 11:54 PM Jianyue Wu <wujianyue000@xxxxxxxxx> wrote:
>
> struct zswap_entry is allocated once per stored page, so any reduction in
> its size is multiplied across every entry zswap holds. 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 small helper that indexes the pools array. The entry holds a
> reference to its pool, which keeps the pool alive and its slot occupied,
> so the lookup is safe without any lock or RCU read-side section.
>
> 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 <chrisl@xxxxxxxxxx>
> Signed-off-by: Jianyue Wu <wujianyue000@xxxxxxxxx>
> ---
> mm/zswap.c | 33 ++++++++++++++++++++++++++-------
> 1 file changed, 26 insertions(+), 7 deletions(-)
>
> diff --git a/mm/zswap.c b/mm/zswap.c
> index 603fdc418041..3974fca40a4a 100644
> --- a/mm/zswap.c
> +++ b/mm/zswap.c
> @@ -213,7 +213,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.
> @@ -222,12 +222,24 @@ 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)
> +{
> + /*
> + * The entry holds a reference to its pool, so the slot cannot be
> + * cleared or reused while the entry is alive: the read is stable
> + * without the pools lock or an RCU read-side section. Non-zero
> + * pool_idx (slot 0 is unused) also marks a live entry for lockdep.
> + */
> + return rcu_dereference_protected(zswap_pools[entry->pool_idx],
> + entry->pool_idx != 0);

Please align the second parameter with the first as long as it doesn't
exceed 100 chars.