From nobody Thu Apr 2 01:46:31 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 BD8BA3A783A; Mon, 9 Mar 2026 12:23:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773058987; cv=none; b=JC4lDk1iAnB9G3NBFwH/X//p43c/Uck75bEx5jELHgsxqUy4JI8iAwOJ4KG4fm4/UO4xJK6IqFUtMgqIJFPraVl98SFVkxd7uQm3l89wJ4DYG0D09xyxf0wJDsQCYP/3Zvq8gFxjObkD97UmzQXZ4FnXVsGPlxqvMWrrn687pRg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773058987; c=relaxed/simple; bh=71ESfdSg+vVssTEg35xko5ianl6haG2mwXQFB0fQSp4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Ljc9+VP+WhpgTzt0d7Uzyg1yoFKMgo3JXphr1AI+IRgs7cw7Ca6Is45l6ngy2O4/gLjZz9OszhK2vuTdrzgM303g2uRcOzisprdH8HJV7kIDD4+HI7qCyz7ttd6MEDws1rqp9LtCm1+mYSCZUJ0dNZE4UrAd+TIpOCe9VL9UX0M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Dl4blc3y; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Dl4blc3y" Received: by smtp.kernel.org (Postfix) with ESMTPS id 5BE6CC2BC9E; Mon, 9 Mar 2026 12:23:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1773058987; bh=71ESfdSg+vVssTEg35xko5ianl6haG2mwXQFB0fQSp4=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=Dl4blc3yxl/25n2L0iC+ggJiPV2jXjI7jJ0BczQpqHY4fJdMmzUG4/MsKpaN98u7I F0WO7nB4lnJ2h+0Lw9iUD5vsOspONHcnfe6xvVCYfKn6W5fMgW9EHpMtzLUeCXFixC HTrpyFEJPC8H2Dg2QjG2AZAhVFDSY6JZVv8E0vgEJxZmAQtD4V+sdKxanxH7T78lgG yYlzDB/fDcXdIhYTeNnPRrcF280mPrYdnfqWs6Kfpv73zfdjqzBsE/d6fRo8zajNfn juBt2VgKRahwxifB79PGurdat8DRbUy0ekDyVH++7y9m9a6eCrM67WFBOCrjtWdOsb YaIqJRITLREEw== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4A90CF3C244; Mon, 9 Mar 2026 12:23:07 +0000 (UTC) From: Jihan LIN via B4 Relay Date: Mon, 09 Mar 2026 12:23:04 +0000 Subject: [PATCH RFC v2 1/5] zram: Rename zcomp_strm_{init, free}() 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="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260309-b4_zcomp_stream-v2-1-7148622326eb@gmail.com> References: <20260309-b4_zcomp_stream-v2-0-7148622326eb@gmail.com> In-Reply-To: <20260309-b4_zcomp_stream-v2-0-7148622326eb@gmail.com> To: Minchan Kim , Sergey Senozhatsky , Jens Axboe Cc: linux-kernel@vger.kernel.org, linux-block@vger.kernel.org, Jihan LIN X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1773058983; l=2360; i=linjh22s@gmail.com; s=linjh22s_machine; h=from:subject:message-id; bh=Z2zJlFN5o7oyquHJ77E4RHCSdek+XUnL3CmLTthvZjM=; b=60RfqiIrFqgkbjJHEzlPVUfSgzje0OaCeVfWhVW0yzCJ1g61IfSGi9uq3jbZYOonDXdkf8B+0 rp4e3qlG1BzB+qfCMewviUA3L2jBR7El3My+vbv+GHRKbS074zs+KyU X-Developer-Key: i=linjh22s@gmail.com; a=ed25519; pk=MnRQAVFy1t4tiGb8ce7ohJwrN2YFXd+dA7XmzR6GmUc= X-Endpoint-Received: by B4 Relay for linjh22s@gmail.com/linjh22s_machine with auth_id=592 X-Original-From: Jihan LIN Reply-To: linjh22s@gmail.com From: Jihan LIN Currently, zcomp uses a preemptive per-CPU stream model where streams are allocated for each online CPU and guarded by mutexes. The existing names zcomp_strm_{init, free}() are too generic to explicitly indicate they handle per-CPU streams. Rename them to zcomp_strm_{init, free}_percpu(). This helps distinguish them from future streams that may not be per-CPU based. No functional changes are intended. Signed-off-by: Jihan LIN --- drivers/block/zram/zcomp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c index a771a8ecc540bad8bf535ec87712da694e34a1d3..f2834898d3b700746db7bd2296e= a9f4186e183c8 100644 --- a/drivers/block/zram/zcomp.c +++ b/drivers/block/zram/zcomp.c @@ -43,7 +43,7 @@ static const struct zcomp_ops *backends[] =3D { NULL }; =20 -static void zcomp_strm_free(struct zcomp *comp, struct zcomp_strm *zstrm) +static void zcomp_strm_free_percpu(struct zcomp *comp, struct zcomp_strm *= zstrm) { comp->ops->destroy_ctx(&zstrm->ctx); vfree(zstrm->local_copy); @@ -51,7 +51,7 @@ static void zcomp_strm_free(struct zcomp *comp, struct zc= omp_strm *zstrm) zstrm->buffer =3D NULL; } =20 -static int zcomp_strm_init(struct zcomp *comp, struct zcomp_strm *zstrm) +static int zcomp_strm_init_percpu(struct zcomp *comp, struct zcomp_strm *z= strm) { int ret; =20 @@ -66,7 +66,7 @@ static int zcomp_strm_init(struct zcomp *comp, struct zco= mp_strm *zstrm) */ zstrm->buffer =3D vzalloc(2 * PAGE_SIZE); if (!zstrm->buffer || !zstrm->local_copy) { - zcomp_strm_free(comp, zstrm); + zcomp_strm_free_percpu(comp, zstrm); return -ENOMEM; } return 0; @@ -172,7 +172,7 @@ int zcomp_cpu_up_prepare(unsigned int cpu, struct hlist= _node *node) struct zcomp_strm *zstrm =3D per_cpu_ptr(comp->stream, cpu); int ret; =20 - ret =3D zcomp_strm_init(comp, zstrm); + ret =3D zcomp_strm_init_percpu(comp, zstrm); if (ret) pr_err("Can't allocate a compression stream\n"); return ret; @@ -184,7 +184,7 @@ int zcomp_cpu_dead(unsigned int cpu, struct hlist_node = *node) struct zcomp_strm *zstrm =3D per_cpu_ptr(comp->stream, cpu); =20 mutex_lock(&zstrm->lock); - zcomp_strm_free(comp, zstrm); + zcomp_strm_free_percpu(comp, zstrm); mutex_unlock(&zstrm->lock); return 0; } --=20 2.51.0 From nobody Thu Apr 2 01:46:31 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 8BE053A4F52; Mon, 9 Mar 2026 12:23:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773058987; cv=none; b=YlOm732mQTlJsQHJgH2SC2qrzw9B648l0v0LWxmwdQ7w4ozIxiy/YJzR1ym4S7cSXUyCY+QwOWHxcMgQwWmHNIQ8GydP4fIPcoiiwPScUV+G9ko9RCZQNG+88RKKL9+GNkZ0s6t0QSmwVPoUZvNEeGqaScywsZk7aePflT+cH+I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773058987; c=relaxed/simple; bh=T0bUAjahBq3JVrUzydh2/RyyXaCrW7y6Yz0eOgay6Rw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=IrRrzZipCLwgdpkXsK7TKDTfEDNXmU52PQlH3CRolcwn5ZImDgo67IzznTmujbUko7YLVQo38w849mXiCO1w+nIKZxo5kFcNZBa/MFBJ8Gu2EbNaebYwWjnZYCqnk/RitTXOEeiajjKwUaPWr+uVrIrSuVMZROSapavjde8Aw9Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=UzZyppj3; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="UzZyppj3" Received: by smtp.kernel.org (Postfix) with ESMTPS id 688D8C2BCAF; Mon, 9 Mar 2026 12:23:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1773058987; bh=T0bUAjahBq3JVrUzydh2/RyyXaCrW7y6Yz0eOgay6Rw=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=UzZyppj3lbSEqPQDFNc887AJuAxl7CkIKOr/fxqmmuL9yWQh1/90Xo4d2wdqV074f yzWp9Qd4rdVl1YyIAf8/n6WwNhYSasJ0tKNpo67/es2h8tiMkjJSL+nB0leFuNJBgk iuu+s2QCZkGmWtc9ZtGTdskVYX2xIsBCYUESQPRTjTzyiyiV9TGQxFVIuLLjieNajk 3rZDyhWCgQcOreJkX4xX/5DDCNOHm6CcSeDJyDfEThAAiC38esLzQ/+ufSecy8ivWz Xw1YoOwvZugb4vISi5puxayfKODf0xwfCwNdVBTl19/ZAke9CVeT7OFaUHftxGBLbp zsaKiJ1JaTw1A== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 58B54F3C247; Mon, 9 Mar 2026 12:23:07 +0000 (UTC) From: Jihan LIN via B4 Relay Date: Mon, 09 Mar 2026 12:23:05 +0000 Subject: [PATCH RFC v2 2/5] zram: Separate the lock from zcomp_strm 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="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260309-b4_zcomp_stream-v2-2-7148622326eb@gmail.com> References: <20260309-b4_zcomp_stream-v2-0-7148622326eb@gmail.com> In-Reply-To: <20260309-b4_zcomp_stream-v2-0-7148622326eb@gmail.com> To: Minchan Kim , Sergey Senozhatsky , Jens Axboe Cc: linux-kernel@vger.kernel.org, linux-block@vger.kernel.org, Jihan LIN X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1773058983; l=5183; i=linjh22s@gmail.com; s=linjh22s_machine; h=from:subject:message-id; bh=cVW7f7+4JOkXg2R6fUKM/sxozdCKUIpNi6O3d3HfKrI=; b=Dn5iWuLr2XotHC043sQvFF0aNY6lPRF1GrPLWZ8P9mNw/e+t2xHlnGV2lkGscE93QoRFSFtw9 vhZYq8U1hnHB4T9aNGG0KQrOSfxX2sGjyIO2EHCFtoHY1TD1qAvtzgT X-Developer-Key: i=linjh22s@gmail.com; a=ed25519; pk=MnRQAVFy1t4tiGb8ce7ohJwrN2YFXd+dA7XmzR6GmUc= X-Endpoint-Received: by B4 Relay for linjh22s@gmail.com/linjh22s_machine with auth_id=592 X-Original-From: Jihan LIN Reply-To: linjh22s@gmail.com From: Jihan LIN Currently zcomp_strm has a lock for default per-CPU streams. This field should not be part of the generic stream structure. Remove lock from zcomp_strm, and introduce struct percpu_zstrm for per-CPU streams. This cleans up struct zcomp_strm and separates the stream definition from its locking policy. Signed-off-by: Jihan LIN --- drivers/block/zram/zcomp.c | 44 +++++++++++++++++++++++++++++-------------= -- drivers/block/zram/zcomp.h | 5 +++-- 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c index f2834898d3b700746db7bd2296ea9f4186e183c8..daea592f01c37106b14dca9c6d8= 727a2240de54b 100644 --- a/drivers/block/zram/zcomp.c +++ b/drivers/block/zram/zcomp.c @@ -43,17 +43,32 @@ static const struct zcomp_ops *backends[] =3D { NULL }; =20 -static void zcomp_strm_free_percpu(struct zcomp *comp, struct zcomp_strm *= zstrm) +struct percpu_zstrm { + struct zcomp_strm strm; + struct mutex lock; +}; + +static struct percpu_zstrm *zstrm_to_pcpu(struct zcomp_strm *zstrm) +{ + return container_of(zstrm, struct percpu_zstrm, strm); +} + +static void zcomp_strm_free_percpu(struct zcomp *comp, + struct percpu_zstrm *zstrm_pcpu) { + struct zcomp_strm *zstrm =3D &zstrm_pcpu->strm; + comp->ops->destroy_ctx(&zstrm->ctx); vfree(zstrm->local_copy); vfree(zstrm->buffer); zstrm->buffer =3D NULL; } =20 -static int zcomp_strm_init_percpu(struct zcomp *comp, struct zcomp_strm *z= strm) +static int zcomp_strm_init_percpu(struct zcomp *comp, + struct percpu_zstrm *zstrm_pcpu) { int ret; + struct zcomp_strm *zstrm =3D &zstrm_pcpu->strm; =20 ret =3D comp->ops->create_ctx(comp->params, &zstrm->ctx); if (ret) @@ -66,7 +81,7 @@ static int zcomp_strm_init_percpu(struct zcomp *comp, str= uct zcomp_strm *zstrm) */ zstrm->buffer =3D vzalloc(2 * PAGE_SIZE); if (!zstrm->buffer || !zstrm->local_copy) { - zcomp_strm_free_percpu(comp, zstrm); + zcomp_strm_free_percpu(comp, zstrm_pcpu); return -ENOMEM; } return 0; @@ -110,7 +125,7 @@ ssize_t zcomp_available_show(const char *comp, char *bu= f, ssize_t at) struct zcomp_strm *zcomp_stream_get(struct zcomp *comp) { for (;;) { - struct zcomp_strm *zstrm =3D raw_cpu_ptr(comp->stream); + struct percpu_zstrm *zstrm_pcpu =3D raw_cpu_ptr(comp->stream); =20 /* * Inspired by zswap @@ -122,16 +137,16 @@ struct zcomp_strm *zcomp_stream_get(struct zcomp *com= p) * from a CPU that has already destroyed its stream. If * so then unlock and re-try on the current CPU. */ - mutex_lock(&zstrm->lock); - if (likely(zstrm->buffer)) - return zstrm; - mutex_unlock(&zstrm->lock); + mutex_lock(&zstrm_pcpu->lock); + if (likely(zstrm_pcpu->strm.buffer)) + return &zstrm_pcpu->strm; + mutex_unlock(&zstrm_pcpu->lock); } } =20 void zcomp_stream_put(struct zcomp_strm *zstrm) { - mutex_unlock(&zstrm->lock); + mutex_unlock(&zstrm_to_pcpu(zstrm)->lock); } =20 int zcomp_compress(struct zcomp *comp, struct zcomp_strm *zstrm, @@ -169,7 +184,7 @@ int zcomp_decompress(struct zcomp *comp, struct zcomp_s= trm *zstrm, int zcomp_cpu_up_prepare(unsigned int cpu, struct hlist_node *node) { struct zcomp *comp =3D hlist_entry(node, struct zcomp, node); - struct zcomp_strm *zstrm =3D per_cpu_ptr(comp->stream, cpu); + struct percpu_zstrm *zstrm =3D per_cpu_ptr(comp->stream, cpu); int ret; =20 ret =3D zcomp_strm_init_percpu(comp, zstrm); @@ -181,11 +196,10 @@ int zcomp_cpu_up_prepare(unsigned int cpu, struct hli= st_node *node) int zcomp_cpu_dead(unsigned int cpu, struct hlist_node *node) { struct zcomp *comp =3D hlist_entry(node, struct zcomp, node); - struct zcomp_strm *zstrm =3D per_cpu_ptr(comp->stream, cpu); + struct percpu_zstrm *zstrm_pcpu =3D per_cpu_ptr(comp->stream, cpu); =20 - mutex_lock(&zstrm->lock); - zcomp_strm_free_percpu(comp, zstrm); - mutex_unlock(&zstrm->lock); + guard(mutex)(&zstrm_pcpu->lock); + zcomp_strm_free_percpu(comp, zstrm_pcpu); return 0; } =20 @@ -193,7 +207,7 @@ static int zcomp_init(struct zcomp *comp, struct zcomp_= params *params) { int ret, cpu; =20 - comp->stream =3D alloc_percpu(struct zcomp_strm); + comp->stream =3D alloc_percpu(struct percpu_zstrm); if (!comp->stream) return -ENOMEM; =20 diff --git a/drivers/block/zram/zcomp.h b/drivers/block/zram/zcomp.h index eacfd3f7d61d9395694292713fb5da4f0023d6d7..9784bc3f432cf0e22085399b877= 2b8ba669071de 100644 --- a/drivers/block/zram/zcomp.h +++ b/drivers/block/zram/zcomp.h @@ -38,7 +38,6 @@ struct zcomp_ctx { }; =20 struct zcomp_strm { - struct mutex lock; /* compression buffer */ void *buffer; /* local copy of handle memory */ @@ -46,6 +45,8 @@ struct zcomp_strm { struct zcomp_ctx ctx; }; =20 +struct percpu_zstrm; + struct zcomp_req { const unsigned char *src; const size_t src_len; @@ -71,7 +72,7 @@ struct zcomp_ops { =20 /* dynamic per-device compression frontend */ struct zcomp { - struct zcomp_strm __percpu *stream; + struct percpu_zstrm __percpu *stream; const struct zcomp_ops *ops; struct zcomp_params *params; struct hlist_node node; --=20 2.51.0 From nobody Thu Apr 2 01:46:31 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 C0E6F3A784E; Mon, 9 Mar 2026 12:23:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773058987; cv=none; b=Mp60CSwVyXsO1tTuShcRbpeg9JN9tjypG6i1pij+0jaf1sQU2IgTc4SF5SMa7V3vetF0c+kUjflHhlAimtdePQ3pMOq/wr2itHpUhcUxvVFdJ5S5IEnjnluKdN6DxsDO2e/g2rsLQ0le4slhdCp2cnY1M1QSlw4laojd+OcsHm8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773058987; c=relaxed/simple; bh=W5kabX0GftY0Q3rvbRArMHbzvWq1EKZb/79piLS8IWY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=TEIhP55lmMpBOYunFJqZi4SQ2AwfKT8AfQ1NYDswBOrb1LbUSpCnPFpzCl14pH9lBkBhl64keIM4YJddkgwhMlxsDEO4WgBbzWIxWQktiqK5TIjRuhcMttdxVxC7kWNAUv7ofwo8F/6c7OsLiHqy3PsNx1Rrik2Ea2qOZ1WRwjM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=rU8Yj1YU; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="rU8Yj1YU" Received: by smtp.kernel.org (Postfix) with ESMTPS id 70B17C2BCB0; Mon, 9 Mar 2026 12:23:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1773058987; bh=W5kabX0GftY0Q3rvbRArMHbzvWq1EKZb/79piLS8IWY=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=rU8Yj1YUZQQ5cIebvVw3YZ8epWaKK5wUob8jqsRKxxcdIQBMBkyaEY8oDxqxNtXg5 V6m/a1OTvix+FX5i5ztP89rYuBgeVDRLPtQtKYI3kaO7anNU05GcECfCruEDqVkbHN tGCAn2XGfkny2azyF5YDaVISKCx7kmm7QYdO8H4Oxww4YndevVFEBIlJFd1Jta0x++ QFeBvAQDFymkUY+aeONhhj9hc/2s5rcUC/nfE5Vlr+3LZIRODdTVLLQUivNs/3wjPQ LsHR3W47w0CnlH7SgkiUbFv0D8IUNmhqImoY0RgtZIyccwXlHsWu6cr77FY9c+XBIH 7tLNKY2Myd53g== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 66AFFF3C245; Mon, 9 Mar 2026 12:23:07 +0000 (UTC) From: Jihan LIN via B4 Relay Date: Mon, 09 Mar 2026 12:23:06 +0000 Subject: [PATCH RFC v2 3/5] zram: Introduce zcomp-managed streams 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="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260309-b4_zcomp_stream-v2-3-7148622326eb@gmail.com> References: <20260309-b4_zcomp_stream-v2-0-7148622326eb@gmail.com> In-Reply-To: <20260309-b4_zcomp_stream-v2-0-7148622326eb@gmail.com> To: Minchan Kim , Sergey Senozhatsky , Jens Axboe Cc: linux-kernel@vger.kernel.org, linux-block@vger.kernel.org, Jihan LIN X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1773058983; l=9074; i=linjh22s@gmail.com; s=linjh22s_machine; h=from:subject:message-id; bh=+EUQ9ObG8GprpcXAW94+J5dWVRBMsH3iSu9ywZbjB8A=; b=RYN+QUVIiYfbGA/89v4IYc5R0SkiW5pSAzbUHrHwQ8Oh8rDq8EQfTUVM4amOSzEAKdit1nbwE NeacQzNmTrMAOKym0JHkV+eubY6iffUCtQdffl5Fx7cIOfPdHbJessn X-Developer-Key: i=linjh22s@gmail.com; a=ed25519; pk=MnRQAVFy1t4tiGb8ce7ohJwrN2YFXd+dA7XmzR6GmUc= X-Endpoint-Received: by B4 Relay for linjh22s@gmail.com/linjh22s_machine with auth_id=592 X-Original-From: Jihan LIN Reply-To: linjh22s@gmail.com From: Jihan LIN Currently, zcomp uses a per-CPU stream model. This design is restrictive for hardware-accelerated or batched zcomp backends. These backends often need to manage their own resources rather than relying on a generic mutex-protected per-CPU stream for batched operations. Extend the zcomp interface to allow backends to optionally manage their own streams while generic per-CPU streams still remain allocated as a complementary mechanism. Introduce zstrm_mgmt flag to struct zcomp_params. Backends set this flag during zcomp_ops->setup_params() to advertise their capability to manage streams. Add zcomp_ops->{get, put}_stream() to allow zcomp backends to implement their own stream strategies. Modify zcomp_stream_get() to accept a new parameter indicating zcomp-managed streams are preferred, and update zcomp_stream_put() to route a zcomp-managed stream to the backend. If the backends advertise their capability and the caller prefers managed streams, try to get a stream from the backends; otherwise, fall back to the generic per-CPU stream. All existing call sites request the default per-CPU stream to preserve the original behavior. Signed-off-by: Jihan LIN --- drivers/block/zram/zcomp.c | 41 +++++++++++++++++++++++++++++++++++++++= -- drivers/block/zram/zcomp.h | 30 ++++++++++++++++++++++++++++-- drivers/block/zram/zram_drv.c | 10 +++++----- 3 files changed, 72 insertions(+), 9 deletions(-) diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c index daea592f01c37106b14dca9c6d8727a2240de54b..1b5c8e8f6c6cb78a812320334da= 0b61391bb38f0 100644 --- a/drivers/block/zram/zcomp.c +++ b/drivers/block/zram/zcomp.c @@ -84,6 +84,7 @@ static int zcomp_strm_init_percpu(struct zcomp *comp, zcomp_strm_free_percpu(comp, zstrm_pcpu); return -ENOMEM; } + zstrm->zcomp_managed =3D false; return 0; } =20 @@ -122,7 +123,7 @@ ssize_t zcomp_available_show(const char *comp, char *bu= f, ssize_t at) return at; } =20 -struct zcomp_strm *zcomp_stream_get(struct zcomp *comp) +static inline struct zcomp_strm *zcomp_stream_pcpu_get(struct zcomp *comp) { for (;;) { struct percpu_zstrm *zstrm_pcpu =3D raw_cpu_ptr(comp->stream); @@ -144,9 +145,37 @@ struct zcomp_strm *zcomp_stream_get(struct zcomp *comp) } } =20 +struct zcomp_strm *zcomp_stream_get(struct zcomp *comp, enum zstrm_pref pr= ef) +{ + if (comp->params->zstrm_mgmt && pref =3D=3D ZSTRM_PREFER_MGMT) { + struct managed_zstrm *zstrm_managed =3D + comp->ops->get_stream(comp->params); + + if (zstrm_managed) { + zstrm_managed->comp =3D comp; + return &zstrm_managed->strm; + } + } + + return zcomp_stream_pcpu_get(comp); +} + +static inline void zcomp_stream_pcpu_put(struct percpu_zstrm *zstrm) +{ + mutex_unlock(&zstrm->lock); +} + void zcomp_stream_put(struct zcomp_strm *zstrm) { - mutex_unlock(&zstrm_to_pcpu(zstrm)->lock); + if (zstrm->zcomp_managed) { + struct managed_zstrm *zstrm_managed =3D + zstrm_to_managed(zstrm); + + zstrm_managed->comp->ops->put_stream( + zstrm_managed->comp->params, zstrm_managed); + } else { + zcomp_stream_pcpu_put(zstrm_to_pcpu(zstrm)); + } } =20 int zcomp_compress(struct zcomp *comp, struct zcomp_strm *zstrm, @@ -211,11 +240,19 @@ static int zcomp_init(struct zcomp *comp, struct zcom= p_params *params) if (!comp->stream) return -ENOMEM; =20 + params->zstrm_mgmt =3D false; comp->params =3D params; ret =3D comp->ops->setup_params(comp->params); if (ret) goto cleanup; =20 + if (params->zstrm_mgmt && + !(comp->ops->get_stream && comp->ops->put_stream)) { + params->zstrm_mgmt =3D false; + pr_warn("Missing managed stream ops in %s, managed stream disabled\n", + comp->ops->name); + } + for_each_possible_cpu(cpu) mutex_init(&per_cpu_ptr(comp->stream, cpu)->lock); =20 diff --git a/drivers/block/zram/zcomp.h b/drivers/block/zram/zcomp.h index 9784bc3f432cf0e22085399b8772b8ba669071de..3543e7e4d2b3b1344bb191b321b= cdd69f67031f6 100644 --- a/drivers/block/zram/zcomp.h +++ b/drivers/block/zram/zcomp.h @@ -24,6 +24,7 @@ struct zcomp_params { union { struct deflate_params deflate; }; + bool zstrm_mgmt; =20 void *drv_data; }; @@ -31,13 +32,14 @@ struct zcomp_params { /* * Run-time driver context - scratch buffers, etc. It is modified during * request execution (compression/decompression), cannot be shared, so - * it's in per-CPU area. + * it's in per-CPU area or managed by the backend. */ struct zcomp_ctx { void *context; }; =20 struct zcomp_strm { + bool zcomp_managed; /* compression buffer */ void *buffer; /* local copy of handle memory */ @@ -47,6 +49,11 @@ struct zcomp_strm { =20 struct percpu_zstrm; =20 +struct managed_zstrm { + struct zcomp *comp; + struct zcomp_strm strm; +}; + struct zcomp_req { const unsigned char *src; const size_t src_len; @@ -55,6 +62,11 @@ struct zcomp_req { size_t dst_len; }; =20 +enum zstrm_pref { + ZSTRM_DEFAULT, /* always use the generic per-CPU stream */ + ZSTRM_PREFER_MGMT, /* try managed stream; fallback to per-CPU */ +}; + struct zcomp_ops { int (*compress)(struct zcomp_params *params, struct zcomp_ctx *ctx, struct zcomp_req *req); @@ -67,6 +79,15 @@ struct zcomp_ops { int (*setup_params)(struct zcomp_params *params); void (*release_params)(struct zcomp_params *params); =20 + /* + * get_stream() needs to prepare zstrm->ctx. The backend must ensure + * returned stream has zcomp_managed set and matches the per-cpu + * stream sizing: local_copy >=3D PAGE_SIZE, buffer >=3D 2 * PAGE_SIZE. + */ + struct managed_zstrm *(*get_stream)(struct zcomp_params *params); + void (*put_stream)(struct zcomp_params *params, + struct managed_zstrm *zstrm); + const char *name; }; =20 @@ -86,7 +107,7 @@ bool zcomp_available_algorithm(const char *comp); struct zcomp *zcomp_create(const char *alg, struct zcomp_params *params); void zcomp_destroy(struct zcomp *comp); =20 -struct zcomp_strm *zcomp_stream_get(struct zcomp *comp); +struct zcomp_strm *zcomp_stream_get(struct zcomp *comp, enum zstrm_pref pr= ef); void zcomp_stream_put(struct zcomp_strm *zstrm); =20 int zcomp_compress(struct zcomp *comp, struct zcomp_strm *zstrm, @@ -94,4 +115,9 @@ int zcomp_compress(struct zcomp *comp, struct zcomp_strm= *zstrm, int zcomp_decompress(struct zcomp *comp, struct zcomp_strm *zstrm, const void *src, unsigned int src_len, void *dst); =20 +static inline struct managed_zstrm *zstrm_to_managed(struct zcomp_strm *zs= trm) +{ + return container_of(zstrm, struct managed_zstrm, strm); +} + #endif /* _ZCOMP_H_ */ diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index bca33403fc8bf872569c63e65af0fe143287eaaf..7be88cfb56adb12fcc1edc6b4d4= 2271044ef71b5 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -1377,7 +1377,7 @@ static int decompress_bdev_page(struct zram *zram, st= ruct page *page, u32 index) size =3D get_slot_size(zram, index); prio =3D get_slot_comp_priority(zram, index); =20 - zstrm =3D zcomp_stream_get(zram->comps[prio]); + zstrm =3D zcomp_stream_get(zram->comps[prio], ZSTRM_DEFAULT); src =3D kmap_local_page(page); ret =3D zcomp_decompress(zram->comps[prio], zstrm, src, size, zstrm->local_copy); @@ -2083,7 +2083,7 @@ static int read_compressed_page(struct zram *zram, st= ruct page *page, u32 index) size =3D get_slot_size(zram, index); prio =3D get_slot_comp_priority(zram, index); =20 - zstrm =3D zcomp_stream_get(zram->comps[prio]); + zstrm =3D zcomp_stream_get(zram->comps[prio], ZSTRM_DEFAULT); src =3D zs_obj_read_begin(zram->mem_pool, handle, size, zstrm->local_copy); dst =3D kmap_local_page(page); @@ -2111,7 +2111,7 @@ static int read_from_zspool_raw(struct zram *zram, st= ruct page *page, u32 index) * case if object spans two physical pages. No decompression * takes place here, as we read raw compressed data. */ - zstrm =3D zcomp_stream_get(zram->comps[ZRAM_PRIMARY_COMP]); + zstrm =3D zcomp_stream_get(zram->comps[ZRAM_PRIMARY_COMP], ZSTRM_DEFAULT); src =3D zs_obj_read_begin(zram->mem_pool, handle, size, zstrm->local_copy); memcpy_to_page(page, 0, src, size); @@ -2265,7 +2265,7 @@ static int zram_write_page(struct zram *zram, struct = page *page, u32 index) if (same_filled) return write_same_filled_page(zram, element, index); =20 - zstrm =3D zcomp_stream_get(zram->comps[ZRAM_PRIMARY_COMP]); + zstrm =3D zcomp_stream_get(zram->comps[ZRAM_PRIMARY_COMP], ZSTRM_DEFAULT); mem =3D kmap_local_page(page); ret =3D zcomp_compress(zram->comps[ZRAM_PRIMARY_COMP], zstrm, mem, &comp_len); @@ -2447,7 +2447,7 @@ static int recompress_slot(struct zram *zram, u32 ind= ex, struct page *page, if (!zram->comps[prio]) continue; =20 - zstrm =3D zcomp_stream_get(zram->comps[prio]); + zstrm =3D zcomp_stream_get(zram->comps[prio], ZSTRM_DEFAULT); src =3D kmap_local_page(page); ret =3D zcomp_compress(zram->comps[prio], zstrm, src, &comp_len_new); --=20 2.51.0 From nobody Thu Apr 2 01:46:31 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 BD94A3A7848; Mon, 9 Mar 2026 12:23:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773058987; cv=none; b=OtVieZQ1n+tNiCbBcxXB6hGpNjhmqjKkqw3VPwEAjMt6fWcBgvFVL74jdRIQDj7pxnrEBUzZnTjjz4jlpuocc3s1eHyvzo/mhbYEBnEnOK2u9MMj/3tvdZnN1/b62P+SZsxB4Yjh8qgECjx9EnJkX2JjbLVygz277gPVWR+lisE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773058987; c=relaxed/simple; bh=6bCovHxNhPnngnBhcdFKTFyFYSTQCtrOJGDsZlVv1hs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=VYgb8gCaKqKImN2Jeq5tckf1zrchE2YiXfTX53Q0OY/9Pt1IZ4L0FrLLI8yyX16EorBYxebW/fVcABAwlYqpYAfmtCBQLUvtwTblLqgrq7QLtPSEDmUYZ0DmC6Siq/jQIGzAEl/57Kq5th59SquUBfp4kHJueSIbKc+Vtw3mZGY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=poo/2el8; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="poo/2el8" Received: by smtp.kernel.org (Postfix) with ESMTPS id 7A418C2BCB1; Mon, 9 Mar 2026 12:23:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1773058987; bh=6bCovHxNhPnngnBhcdFKTFyFYSTQCtrOJGDsZlVv1hs=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=poo/2el8/wjy6eJ3xHpHslaH7yLU6gPqHFARnpZN2EnfSF22x08NAkqILuphn+RFq rCSZrXpbQhlAUXu0sguEnAccvdi3wx/EgXl3EiQixjJIx1hY65/p74XKA6Oxg4AMmu 56p1cTe6+dn5Zq5bsNdz952xggOUQnMJA7IScsGZfJOf5YNxTY5DwhK5VObpRe15pr hRTpPP+Li2kW6FOyTXpqjFC0PxqPno8M702WwMwwE/hUHMdbSywvSl1RfPphDAEx/k uYcTC+cj8+QbL+cCr8K6ljkgyaspC9T/oOOVwUGm11DAOPj9ZpeQ636g7AaStbnU2w dXcbSaQcH7G2w== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 73598F3C249; Mon, 9 Mar 2026 12:23:07 +0000 (UTC) From: Jihan LIN via B4 Relay Date: Mon, 09 Mar 2026 12:23:07 +0000 Subject: [PATCH RFC v2 4/5] zram: Use zcomp-managed streams for async write requests 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="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260309-b4_zcomp_stream-v2-4-7148622326eb@gmail.com> References: <20260309-b4_zcomp_stream-v2-0-7148622326eb@gmail.com> In-Reply-To: <20260309-b4_zcomp_stream-v2-0-7148622326eb@gmail.com> To: Minchan Kim , Sergey Senozhatsky , Jens Axboe Cc: linux-kernel@vger.kernel.org, linux-block@vger.kernel.org, Jihan LIN X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1773058983; l=3798; i=linjh22s@gmail.com; s=linjh22s_machine; h=from:subject:message-id; bh=v0DGgSS+E5bgvt8cBKnXuZ6r8eM9BVP7bcdiMehO2N4=; b=zwljVfG1zncWfD57mFttrzMqxef6yb2k6deJ19Qm8qYfJy3u8QDJK3byb+yduxIK6Tvk0LF7w N5PKY/tv4cBAJG1Rg5GthxCscul2Qk0o6fzkDouOpzjWoEkEIh/GK1/ X-Developer-Key: i=linjh22s@gmail.com; a=ed25519; pk=MnRQAVFy1t4tiGb8ce7ohJwrN2YFXd+dA7XmzR6GmUc= X-Endpoint-Received: by B4 Relay for linjh22s@gmail.com/linjh22s_machine with auth_id=592 X-Original-From: Jihan LIN Reply-To: linjh22s@gmail.com From: Jihan LIN Current per-CPU streams limit write concurrency to the number of online CPUs. Hardware accelerators with deep submission queues can handle far more concurrent requests. Use zcomp-managed streams for async write requests to take advantage of this. Modify zram_write_page() to accept a flag indicating the request is asynchronous. If the bio request is considered non-synchronous and the backend supports zcomp-managed streams, attempt to acquire one. zcomp_stream_get() handles the fallback to per-CPU streams. Sync writes block waiting for completion (e.g., blk_wait_io() in submit_bio_wait() from callers), and remain on per-CPU streams for per-request latency. Reads are unchanged since they are treated as synchronous operations. Recompression also remains unchanged as it prioritizes compression ratio. Although zram_write_page() currently waits for compression to complete, using zcomp-managed streams allows write concurrency to exceed the number of CPUs. Supporting multiple pages within a single bio request is deferred to keep it simple and focused. Signed-off-by: Jihan LIN --- drivers/block/zram/zram_drv.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index 7be88cfb56adb12fcc1edc6b4d42271044ef71b5..3db4579776f758c16006fd3108b= 4f778b84fea30 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -2083,6 +2083,7 @@ static int read_compressed_page(struct zram *zram, st= ruct page *page, u32 index) size =3D get_slot_size(zram, index); prio =3D get_slot_comp_priority(zram, index); =20 + /* Reads are treated as synchronous, see op_is_sync(). */ zstrm =3D zcomp_stream_get(zram->comps[prio], ZSTRM_DEFAULT); src =3D zs_obj_read_begin(zram->mem_pool, handle, size, zstrm->local_copy); @@ -2249,7 +2250,8 @@ static int write_incompressible_page(struct zram *zra= m, struct page *page, return 0; } =20 -static int zram_write_page(struct zram *zram, struct page *page, u32 index) +static int zram_write_page(struct zram *zram, struct page *page, u32 index, + bool is_async) { int ret =3D 0; unsigned long handle; @@ -2265,7 +2267,16 @@ static int zram_write_page(struct zram *zram, struct= page *page, u32 index) if (same_filled) return write_same_filled_page(zram, element, index); =20 - zstrm =3D zcomp_stream_get(zram->comps[ZRAM_PRIMARY_COMP], ZSTRM_DEFAULT); + /* + * Using a zcomp-managed stream and waiting for compression makes this + * appear synchronous. + * + * At this time, zram_bio_write handles pages one by one. + * However, preferring zcomp-managed streams allows backends to utilize + * their own resources. + */ + zstrm =3D zcomp_stream_get(zram->comps[ZRAM_PRIMARY_COMP], + is_async ? ZSTRM_PREFER_MGMT : ZSTRM_DEFAULT); mem =3D kmap_local_page(page); ret =3D zcomp_compress(zram->comps[ZRAM_PRIMARY_COMP], zstrm, mem, &comp_len); @@ -2327,7 +2338,8 @@ static int zram_bvec_write_partial(struct zram *zram,= struct bio_vec *bvec, ret =3D zram_read_page(zram, page, index, bio); if (!ret) { memcpy_from_bvec(page_address(page) + offset, bvec); - ret =3D zram_write_page(zram, page, index); + ret =3D zram_write_page(zram, page, index, + !op_is_sync(bio->bi_opf)); } __free_page(page); return ret; @@ -2338,7 +2350,8 @@ static int zram_bvec_write(struct zram *zram, struct = bio_vec *bvec, { if (is_partial_io(bvec)) return zram_bvec_write_partial(zram, bvec, index, offset, bio); - return zram_write_page(zram, bvec->bv_page, index); + return zram_write_page(zram, bvec->bv_page, index, + !op_is_sync(bio->bi_opf)); } =20 #ifdef CONFIG_ZRAM_MULTI_COMP --=20 2.51.0 From nobody Thu Apr 2 01:46:31 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 B0AFF3A7828; Mon, 9 Mar 2026 12:23:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773058987; cv=none; b=WNwGLoTBWVA/wc7Q4BUNz4pWrNsmhzAqoUekn8KZWnAl6XtekGaPxc1btUKsZrk0xiVsRbUWt8RC4AIw+sezfMINb6tmr2r00YTb66lpwQ2AlgkL23+SxU1F1KGa4T7sI9WlG2/W+9HjQTC+vS1tYWON1HeS+xXanipad+9oYmU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773058987; c=relaxed/simple; bh=2JNnv0JCBl4j8Pa9FlpUhpGt81JKhtdQrMm9GoVFe2s=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=cVQ2jnNgaXjwcWqz8NjbCtlyZAXc2oJzYmwZbr/ybdYl+xz1qteFN6nUPGup9dITg9DAcXJCHWvF615h8sdNz8SIKt9IPyTBwhGFtgEzbpi6/mXBOb7tM8z/RCPxHkMa+JOiUwSC+9yYLG9jijXTB2Zak8igN62ytQ2Q592p2to= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ExKPuVLN; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ExKPuVLN" Received: by smtp.kernel.org (Postfix) with ESMTPS id 8C528C2BCB3; Mon, 9 Mar 2026 12:23:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1773058987; bh=2JNnv0JCBl4j8Pa9FlpUhpGt81JKhtdQrMm9GoVFe2s=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=ExKPuVLN3osV1nnf1uvMQ91gs/JHbV/5sH+tkxsnBqcVxMQZszKtj/l9JzAOlpGiA gu27d06nv1R50J3sUbPX+fSJq6vasDeNPDbaT50Uwq2iDbcPFAx1RA+LOYsdWp6pSg ukriNAqaLvqV/CJRVH8Mi2RnF9VdKGYu1Xue2+TjzjnfrU9NKNtF8DunnCJECKLorG bkIA9TscMAxluHVYxFW5fupguubN93GoSPwPbaY6QC5EmexcUn0Bz+Ejvhrb8NTIaB kA0miiC1xm4aYqx8I0Rn0r0RMjFh91lL48yiKlYGd/kEwDJuMuaBjcF6PEaWGUnXKu soagwwgbzXxGQ== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 83BEBF3C247; Mon, 9 Mar 2026 12:23:07 +0000 (UTC) From: Jihan LIN via B4 Relay Date: Mon, 09 Mar 2026 12:23:08 +0000 Subject: [PATCH RFC v2 5/5] zram: Add lz4 PoC for zcomp-managed streams 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="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260309-b4_zcomp_stream-v2-5-7148622326eb@gmail.com> References: <20260309-b4_zcomp_stream-v2-0-7148622326eb@gmail.com> In-Reply-To: <20260309-b4_zcomp_stream-v2-0-7148622326eb@gmail.com> To: Minchan Kim , Sergey Senozhatsky , Jens Axboe Cc: linux-kernel@vger.kernel.org, linux-block@vger.kernel.org, Jihan LIN X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1773058983; l=14336; i=linjh22s@gmail.com; s=linjh22s_machine; h=from:subject:message-id; bh=mEMDbmD1qoxl2reBWd5JjsA+BTrp9Jpy4oVUppxc3RM=; b=gH9uVl9GuizfjHXZlitR7fYS65n626SGU0aO3epsRXcwPen+cd/H8uMLnApxo2tr66Av23nvJ mYYWce/CxmeCr9KhGQAjXsdDn+LP+Tz0ZyY6/RzTk4UrFvL258XXt1Z X-Developer-Key: i=linjh22s@gmail.com; a=ed25519; pk=MnRQAVFy1t4tiGb8ce7ohJwrN2YFXd+dA7XmzR6GmUc= X-Endpoint-Received: by B4 Relay for linjh22s@gmail.com/linjh22s_machine with auth_id=592 X-Original-From: Jihan LIN Reply-To: linjh22s@gmail.com From: Jihan LIN This patch provides a proof-of-concept implementation of zcomp-managed streams for the lz4 backend, demonstrating how a hardware-accelerated compression backend would integrate with zcomp-managed streams introduced earlier in this series. The PoC simulates a hardware accelerator with a fixed queue depth of 128. Global stream buffers are shared across all zram devices, while contexts are per-device. Both are pre-allocated. During compression, requests are submitted to a double-buffered kfifo queue and processed by a dedicated kthread. Known limitations: - The single kthread serializes all compression work. - Pool sizes are hard-coded. - Uses global mutexes; contention is expected to be high under load. - Assumes !HIGHMEM; kmap_local_page mappings are passed to a kthread. Signed-off-by: Jihan LIN --- drivers/block/zram/backend_lz4.c | 464 +++++++++++++++++++++++++++++++++++= ++-- 1 file changed, 442 insertions(+), 22 deletions(-) diff --git a/drivers/block/zram/backend_lz4.c b/drivers/block/zram/backend_= lz4.c index 04e18661476086502ac41355e9cc38cc2f353d52..adf689003a62770cbbf0901ca07= da84108f8d9d7 100644 --- a/drivers/block/zram/backend_lz4.c +++ b/drivers/block/zram/backend_lz4.c @@ -2,8 +2,12 @@ #include #include #include +#include +#include +#include =20 #include "backend_lz4.h" +#include "zcomp.h" =20 struct lz4_ctx { void *mem; @@ -12,18 +16,326 @@ struct lz4_ctx { LZ4_stream_t *cstrm; }; =20 +struct lz4_stream { + struct managed_zstrm zstrm; + struct list_head node; + struct completion completion; + int result; +}; + +struct lz4_req { + struct lz4_stream *strm; + struct lz4_ctx *ctx; + struct zcomp_params *params; + struct zcomp_req *zreq; +}; + +#define BACKEND_LZ4_STREAM_MAX 128 +#define BACKEND_LZ4_QUEUE_NR 2 + +struct lz4_global { + struct list_head stream_head; + struct mutex stream_lock; + struct task_struct *tsk; + + struct completion new_task_ready; + + struct mutex working_lock; + DECLARE_KFIFO(working_queue[BACKEND_LZ4_QUEUE_NR], struct lz4_req, + BACKEND_LZ4_STREAM_MAX); + int working_submit_idx; + + struct kref ref; +}; + +static DEFINE_MUTEX(lz4_global_lock); +static struct lz4_global *lz4_global_data; + +static void lz4_stream_free(struct lz4_stream *src) +{ + if (IS_ERR_OR_NULL(src)) + return; + + vfree(src->zstrm.strm.buffer); + vfree(src->zstrm.strm.local_copy); + + kvfree(src); +} + +DEFINE_FREE(lz4_stream, struct lz4_stream *, lz4_stream_free(_T)); +static struct lz4_stream *lz4_stream_alloc(void) +{ + struct lz4_stream *strm __free(lz4_stream) =3D NULL; + void *buffer __free(kvfree) =3D NULL; + void *local_copy __free(kvfree) =3D NULL; + + strm =3D kvzalloc_obj(struct lz4_stream, GFP_KERNEL); + if (!strm) + return ERR_PTR(-ENOMEM); + + buffer =3D vmalloc(PAGE_SIZE * 2); + local_copy =3D vmalloc(PAGE_SIZE); + if (!buffer || !local_copy) + return ERR_PTR(-ENOMEM); + + strm->zstrm.strm.buffer =3D no_free_ptr(buffer); + strm->zstrm.strm.local_copy =3D no_free_ptr(local_copy); + strm->zstrm.strm.zcomp_managed =3D true; + + return_ptr(strm); +} + +static void lz4_streams_destroy(struct lz4_global *inst) +{ + struct lz4_stream *pos, *tmp; + + list_for_each_entry_safe(pos, tmp, &inst->stream_head, node) { + list_del(&pos->node); + lz4_stream_free(pos); + } +} + +static int lz4_streams_init(struct zcomp_params *params, + struct lz4_global *inst) +{ + int err =3D 0; + + INIT_LIST_HEAD(&inst->stream_head); + for (int i =3D 0; i < BACKEND_LZ4_STREAM_MAX; i++) { + struct lz4_stream *curr_zstrm __free(lz4_stream) =3D NULL; + + curr_zstrm =3D lz4_stream_alloc(); + if (IS_ERR(curr_zstrm)) { + err =3D PTR_ERR(curr_zstrm); + break; + } + + /* lz4_ctx is linked to stream in get_stream() */ + list_add(&curr_zstrm->node, &inst->stream_head); + init_completion(&curr_zstrm->completion); + retain_and_null_ptr(curr_zstrm); + } + + if (err) { + lz4_streams_destroy(inst); + return err; + } + + return 0; +} + +static int __lz4_compress(struct zcomp_params *params, struct lz4_ctx *zct= x, + struct zcomp_req *req); + +static void lz4_do_compression(struct lz4_global *inst) +{ + struct lz4_req req; + int idx; + + scoped_guard(mutex, &inst->working_lock) + { + idx =3D inst->working_submit_idx; + inst->working_submit_idx =3D (idx + 1) % BACKEND_LZ4_QUEUE_NR; + } + + while (kfifo_get(&inst->working_queue[idx], &req)) { + struct lz4_stream *lz4_strm =3D req.strm; + + lz4_strm->result =3D + __lz4_compress(req.params, req.ctx, req.zreq); + complete(&lz4_strm->completion); + } +} + +static int lz4_thread_worker(void *data) +{ + struct lz4_global *inst =3D data; + + while (!kthread_should_stop()) { + int err; + + err =3D wait_for_completion_interruptible(&inst->new_task_ready); + if (err) + continue; + lz4_do_compression(inst); + } + return 0; +} + +static int lz4_global_init(struct zcomp_params *params) +{ + int err =3D 0; + struct lz4_global *newinst =3D NULL; + + mutex_lock(&lz4_global_lock); + + if (lz4_global_data) { + kref_get(&lz4_global_data->ref); + err =3D 0; + goto out_unlock; + } + + newinst =3D kvzalloc_obj(*newinst); + if (!newinst) { + err =3D -ENOMEM; + goto out_unlock; + } + + INIT_KFIFO(newinst->working_queue[0]); + INIT_KFIFO(newinst->working_queue[1]); + newinst->working_submit_idx =3D 0; + + mutex_init(&newinst->stream_lock); + mutex_init(&newinst->working_lock); + kref_init(&newinst->ref); + err =3D lz4_streams_init(params, newinst); + if (err) + goto err_stream_init; + init_completion(&newinst->new_task_ready); + newinst->tsk =3D kthread_run(lz4_thread_worker, newinst, "zcomp_lz4"); + if (IS_ERR(newinst->tsk)) { + err =3D PTR_ERR(newinst->tsk); + goto err_kthread_init; + } + + lz4_global_data =3D newinst; + mutex_unlock(&lz4_global_lock); + return 0; + +err_kthread_init: + lz4_streams_destroy(newinst); +err_stream_init: + mutex_destroy(&newinst->working_lock); + mutex_destroy(&newinst->stream_lock); + kvfree(newinst); +out_unlock: + mutex_unlock(&lz4_global_lock); + return err; +} + +static void lz4_global_destroy(struct kref *ref) +{ + struct lz4_global *inst; + + lockdep_assert_held(&lz4_global_lock); + + if (!lz4_global_data) + return; + inst =3D container_of(ref, struct lz4_global, ref); + WARN_ON(inst !=3D lz4_global_data); + + lz4_global_data =3D NULL; + kthread_stop(inst->tsk); + lz4_streams_destroy(inst); + mutex_destroy(&inst->stream_lock); + mutex_destroy(&inst->working_lock); + kvfree(inst); +} + +struct lz4_drv { + struct mutex lock; + DECLARE_KFIFO(ctxqueue, struct lz4_ctx *, BACKEND_LZ4_STREAM_MAX); + struct lz4_ctx ctxs[BACKEND_LZ4_STREAM_MAX]; +}; + +static int lz4_ctx_init(struct zcomp_params *params, struct lz4_ctx *zctx); +static void lz4_ctx_destroy(struct lz4_ctx *zctx); + +static void lz4_drv_free(struct lz4_drv *drv_data) +{ + int i; + + for (i =3D 0; i < ARRAY_SIZE(drv_data->ctxs); i++) + lz4_ctx_destroy(&drv_data->ctxs[i]); + + mutex_destroy(&drv_data->lock); + + kvfree(drv_data); +} + +static int lz4_drv_alloc(struct zcomp_params *params) +{ + struct lz4_drv *drv_data =3D NULL; + int i, len; + int err =3D 0; + + drv_data =3D kvzalloc_obj(*drv_data); + if (!drv_data) + return -ENOMEM; + mutex_init(&drv_data->lock); + + INIT_KFIFO(drv_data->ctxqueue); + + len =3D kfifo_size(&drv_data->ctxqueue); + + for (i =3D 0; i < min(len, ARRAY_SIZE(drv_data->ctxs)); i++) { + struct lz4_ctx *ctx =3D &drv_data->ctxs[i]; + + err =3D lz4_ctx_init(params, ctx); + if (err) + break; + + kfifo_put(&drv_data->ctxqueue, ctx); + } + + if (err) { + lz4_drv_free(drv_data); + return err; + } + + params->drv_data =3D drv_data; + + return 0; +} + static void lz4_release_params(struct zcomp_params *params) { + struct lz4_drv *drv_data =3D params->drv_data; + + if (!params->zstrm_mgmt) + return; + + lz4_drv_free(drv_data); + + kref_put_mutex(&lz4_global_data->ref, lz4_global_destroy, + &lz4_global_lock); } =20 static int lz4_setup_params(struct zcomp_params *params) { + int err =3D 0; + if (params->level =3D=3D ZCOMP_PARAM_NOT_SET) params->level =3D LZ4_ACCELERATION_DEFAULT; =20 + params->zstrm_mgmt =3D false; + err =3D lz4_global_init(params); + if (err) { + pr_err("lz4 global init failed: %d, managed stream disabled", + err); + return 0; + } + + err =3D lz4_drv_alloc(params); + + if (err) { + pr_err("lz4 drv init failed: %d, managed stream disabled", err); + kref_put_mutex(&lz4_global_data->ref, lz4_global_destroy, + &lz4_global_lock); + return 0; + } + + params->zstrm_mgmt =3D true; return 0; } =20 +static void lz4_ctx_destroy(struct lz4_ctx *zctx) +{ + vfree(zctx->mem); + kfree(zctx->dstrm); + kfree(zctx->cstrm); +} + static void lz4_destroy(struct zcomp_ctx *ctx) { struct lz4_ctx *zctx =3D ctx->context; @@ -31,12 +343,36 @@ static void lz4_destroy(struct zcomp_ctx *ctx) if (!zctx) return; =20 - vfree(zctx->mem); - kfree(zctx->dstrm); - kfree(zctx->cstrm); + lz4_ctx_destroy(zctx); kfree(zctx); } =20 +static int lz4_ctx_init(struct zcomp_params *params, struct lz4_ctx *zctx) +{ + void *mem __free(kvfree) =3D NULL; + LZ4_streamDecode_t *dstrm __free(kfree) =3D NULL; + LZ4_stream_t *cstrm __free(kfree) =3D NULL; + + if (params->dict_sz =3D=3D 0) { + mem =3D vmalloc(LZ4_MEM_COMPRESS); + if (!mem) + return -ENOMEM; + } else { + dstrm =3D kzalloc_obj(*zctx->dstrm); + if (!dstrm) + return -ENOMEM; + + cstrm =3D kzalloc_obj(*zctx->cstrm); + if (!cstrm) + return -ENOMEM; + } + + zctx->mem =3D no_free_ptr(mem); + zctx->dstrm =3D no_free_ptr(dstrm); + zctx->cstrm =3D no_free_ptr(cstrm); + return 0; +} + static int lz4_create(struct zcomp_params *params, struct zcomp_ctx *ctx) { struct lz4_ctx *zctx; @@ -46,31 +382,17 @@ static int lz4_create(struct zcomp_params *params, str= uct zcomp_ctx *ctx) return -ENOMEM; =20 ctx->context =3D zctx; - if (params->dict_sz =3D=3D 0) { - zctx->mem =3D vmalloc(LZ4_MEM_COMPRESS); - if (!zctx->mem) - goto error; - } else { - zctx->dstrm =3D kzalloc_obj(*zctx->dstrm); - if (!zctx->dstrm) - goto error; - - zctx->cstrm =3D kzalloc_obj(*zctx->cstrm); - if (!zctx->cstrm) - goto error; + if (lz4_ctx_init(params, zctx)) { + lz4_destroy(ctx); + return -ENOMEM; } =20 return 0; - -error: - lz4_destroy(ctx); - return -ENOMEM; } =20 -static int lz4_compress(struct zcomp_params *params, struct zcomp_ctx *ctx, - struct zcomp_req *req) +static int __lz4_compress(struct zcomp_params *params, struct lz4_ctx *zct= x, + struct zcomp_req *req) { - struct lz4_ctx *zctx =3D ctx->context; int ret; =20 if (!zctx->cstrm) { @@ -92,6 +414,47 @@ static int lz4_compress(struct zcomp_params *params, st= ruct zcomp_ctx *ctx, return 0; } =20 +static int lz4_compress_managed(struct zcomp_params *params, + struct lz4_ctx *zctx, struct zcomp_req *req, + struct zcomp_strm *zstrm) +{ + struct lz4_stream *mngt_strm =3D + container_of(zstrm_to_managed(zstrm), struct lz4_stream, zstrm); + + scoped_guard(mutex, &lz4_global_data->working_lock) + { + int cnt; + int idx =3D lz4_global_data->working_submit_idx; + struct lz4_req lz4req =3D { + .strm =3D mngt_strm, + .params =3D params, + .ctx =3D zctx, + .zreq =3D req + }; + + /* ctx->src is mapped by kmap_local_map() */ + BUILD_BUG_ON(IS_ENABLED(CONFIG_HIGHMEM)); + cnt =3D kfifo_put(&lz4_global_data->working_queue[idx], lz4req); + if (cnt =3D=3D 0) + return -EBUSY; + } + complete(&lz4_global_data->new_task_ready); + wait_for_completion(&mngt_strm->completion); + return mngt_strm->result; +} + +static int lz4_compress(struct zcomp_params *params, struct zcomp_ctx *ctx, + struct zcomp_req *req) +{ + struct lz4_ctx *zctx =3D ctx->context; + struct zcomp_strm *zstrm =3D container_of(ctx, struct zcomp_strm, ctx); + + if (!zstrm->zcomp_managed) + return __lz4_compress(params, zctx, req); + + return lz4_compress_managed(params, zctx, req, zstrm); +} + static int lz4_decompress(struct zcomp_params *params, struct zcomp_ctx *c= tx, struct zcomp_req *req) { @@ -116,6 +479,61 @@ static int lz4_decompress(struct zcomp_params *params,= struct zcomp_ctx *ctx, return 0; } =20 +static struct managed_zstrm *lz4_get_stream(struct zcomp_params *params) +{ + struct lz4_stream *lz4_strm; + struct lz4_drv *drv_data =3D params->drv_data; + struct lz4_ctx *ctx; + + if (!params->zstrm_mgmt) + return NULL; + + scoped_guard(mutex, &lz4_global_data->stream_lock) + { + lz4_strm =3D list_first_entry_or_null( + &lz4_global_data->stream_head, struct lz4_stream, node); + if (!lz4_strm) + return NULL; + + list_del_init(&lz4_strm->node); + } + + scoped_guard(mutex, &drv_data->lock) + if (!kfifo_get(&drv_data->ctxqueue, &ctx)) + ctx =3D NULL; + if (!ctx) { + guard(mutex)(&lz4_global_data->stream_lock); + list_add(&lz4_strm->node, &lz4_global_data->stream_head); + return NULL; + } + reinit_completion(&lz4_strm->completion); + lz4_strm->zstrm.strm.ctx.context =3D ctx; + + return &lz4_strm->zstrm; +} + +static void lz4_put_stream(struct zcomp_params *params, + struct managed_zstrm *zstrm) +{ + struct lz4_stream *lz4_strm; + struct lz4_ctx *ctx; + struct lz4_drv *drv_data =3D params->drv_data; + + if (!zstrm) + return; + if (WARN_ON(!params->zstrm_mgmt)) + return; + + lz4_strm =3D container_of(zstrm, struct lz4_stream, zstrm); + ctx =3D zstrm->strm.ctx.context; + lz4_strm->zstrm.strm.ctx.context =3D NULL; + + scoped_guard(mutex, &lz4_global_data->stream_lock) + list_add(&lz4_strm->node, &lz4_global_data->stream_head); + scoped_guard(mutex, &drv_data->lock) + kfifo_put(&drv_data->ctxqueue, ctx); +} + const struct zcomp_ops backend_lz4 =3D { .compress =3D lz4_compress, .decompress =3D lz4_decompress, @@ -123,5 +541,7 @@ const struct zcomp_ops backend_lz4 =3D { .destroy_ctx =3D lz4_destroy, .setup_params =3D lz4_setup_params, .release_params =3D lz4_release_params, + .get_stream =3D lz4_get_stream, + .put_stream =3D lz4_put_stream, .name =3D "lz4", }; --=20 2.51.0