From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1793329375; b=E4Y/jDfXT6X1sLy5VQfsf8W5zvoEgsgZsp0h5HwmwM3HRVKKZavPorxlPaBxexThdVNG E5IQBblFw+yFBUV7DXRTUtYu2Ty7+9I9gtS4zc7JvB/8x/+3Nr9zNENTshpNgllyHjAsF HFIAdQIum1DQCCE7ZLP7mrKjrZzacZkEgpogvrXuhysAMt3q+zVY1WOmkrns2p5Bv3olt 8K2bWyRy8mRyxwNb3EycL6w5H12DVMQWUYeP4s/0gwOtMKrlKAhXMJFeWE5q+et7bTqtJ JzTvNJheTeIXI4PehT443DJaOmXMwwZL3f8wibdS6aZSfE5h7uIEKmRJYDg728SX14w== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793329375; h=Received:DKIM-Signature:Date:To:From:Subject:Message-Id; bh=9dRDoe1l9JKGOZU8Q9n9o2Mltlkq2f5MYRjSf2cNXMk=; b=Hm74cxDb88+lCPwZ1PTF6wjEzciKmEO04FRxTo85EzBFAWmSNeXgHalcZHzv6CooFVcL nGenjmDzKxni93hSecBedIsAzMhaCLWOREphQJNVOLzRxbcM+1rZlDMj5WhWW/1Xeabi5 UeYE58st/eXY2xHtsgBcdldVFKiGTSPDvflt63PZiTqYauqGE+msM5RUKiFxUMyJwHvpp A8t/kpg0dIqIgrJ/+bZK/eSN6U1pczyYAkQhN4I3fKq0s2zelgsZ9cjL7w0VjPh7ncmeC uuTX8D5SQeLpEuhspC2/IYOtlKZbxnpuQklFWfLNIbwXYBJrGvU4UhBYCyrAIYqge8Q== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=linux-foundation.org header.i=@linux-foundation.org header.a=rsa-sha256 header.s=korg header.b=dc8FGT+R; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2ED6A606A31C for ; Fri, 30 Oct 2026 03:02:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key, unprotected) header.d=linux-foundation.org header.i=@linux-foundation.org header.a=rsa-sha256 header.s=korg header.b=dc8FGT+R Received: by smtp.kernel.org (Postfix) with ESMTPSA id A16FE1F000C1; Fri, 30 Oct 2026 03:02:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux-foundation.org; s=korg; t=1793329374; bh=9dRDoe1l9JKGOZU8Q9n9o2Mltlkq2f5MYRjSf2cNXMk=; h=Date:To:From:Subject; b=dc8FGT+RznnqEMMHGKxoQ+6+QA2D7IYVtXBcXa1O94udqDxXOOoSKitCcZjyLaVjZ i3tBjBYQsmhcxqOstkH8TDkVNdaMXHjpwWxFtEtW1/gM2oPRyO5bzObItpQ9jYaZl9 OaSa6rQg9p/Kj6PTNi+xHipLQCRJpN66hpRZERos= Date: Thu, 29 Oct 2026 20:02:54 -0700 To: mm-commits@vger.kernel.org,zhangbo56@xiaomi.com,zhangbo0325@gmail.com, richardycc@google.com,minchan@kernel.org,hdanton@sina.com,bgeffon@google.com, baohua@kernel.org,senozhatsky@chromium.org,akpm@linux-foundation.org From: Andrew Morton Subject: + zram-use-a-singleton-compression-context-for-recompression.patch added to mm-nonmm-unstable branch Message-Id: <20261030030254.A16FE1F000C1@smtp.kernel.org> X-Mailing-List: mm-commits@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list The patch titled Subject: zram: use a singleton compression context for recompression has been added to the -mm mm-nonmm-unstable branch. Its filename is zram-use-a-singleton-compression-context-for-recompression.patch This patch will shortly appear at https://git.kernel.org/pub/scm/linux/kernel/git/akpm/25-new.git/tree/patches/zram-use-a-singleton-compression-context-for-recompression.patch This patch will later appear in the mm-nonmm-unstable branch at git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm Before you just go and hit "reply", please: a) Consider who else should be cc'ed b) Prefer to cc a suitable mailing list as well c) Ideally: find the original patch on the mailing list and do a reply-to-all to that, adding suitable additional cc's *** Remember to use Documentation/process/submit-checklist.rst when testing your code *** The -mm tree is included into linux-next via various branches at git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm and is updated there most days ------------------------------------------------------ From: Sergey Senozhatsky Subject: zram: use a singleton compression context for recompression Date: Sun, 25 Oct 2026 11:18:31 +0900 Secondary compressors are only used by recompress_store(), which is serialized under zram->dev_lock, so we only ever use one secondary compressor at a time, yet we still allocate them on each CPU, which is just a plain memory wastage. However, we do need per-CPU decompressors in order to support concurrent reads. Now that Read and Write contexts are split, we can allocate just a single compression stream (recomp_cstream) for secondary algorithms instead of per-CPU streams, avoiding unused per-CPU compression contexts and 2 * PAGE_SIZE buffers. For example, on an 8-CPU x86_64 system (4K PAGE_SIZE), this saves: - zstd (level 3, default): ~700 KB (~100 KB/CPU) - zstd (levels 12-22, no dict): ~1.91 MB (~280 KB/CPU) - zstd (levels 14-22, 110K dict): ~5.33 MB (~780 KB/CPU, lazy) - deflate (winbits=-11, default): ~1.04 MB (~152 KB/CPU) - deflate (winbits=15): ~1.86 MB (~272 KB/CPU) - lz4hc: ~1.84 MB (~269 KB/CPU) Link: https://lore.kernel.org/20261025021839.1542805-16-senozhatsky@chromium.org Signed-off-by: Sergey Senozhatsky Signed-off-by: Andrew Morton Cc: Brian Geffon Cc: Barry Song Cc: Bo Zhang Cc: Minchan Kim Cc: Richard Chang Cc: Bo Zhang Cc: Hillf Danton --- drivers/block/zram/zcomp.c | 75 +++++++++++++++++++++++--------- drivers/block/zram/zcomp.h | 9 ++- drivers/block/zram/zram_drv.c | 5 +- 3 files changed, 65 insertions(+), 24 deletions(-) --- a/drivers/block/zram/zcomp.c~zram-use-a-singleton-compression-context-for-recompression +++ a/drivers/block/zram/zcomp.c @@ -151,6 +151,11 @@ ssize_t zcomp_available_show(const char struct zcomp_cstrm *zcomp_cstrm_get(struct zcomp *comp) { + if (comp->recomp_cstream) { + mutex_lock(&comp->recomp_cstream->lock); + return comp->recomp_cstream; + } + for (;;) { struct zcomp_cstrm *zstrm = raw_cpu_ptr(comp->cstream); @@ -326,22 +331,25 @@ int zcomp_decompress(struct zcomp *comp, int zcomp_cpu_up_prepare(unsigned int cpu, struct hlist_node *node) { struct zcomp *comp = hlist_entry(node, struct zcomp, node); - struct zcomp_cstrm *cstrm; + struct zcomp_cstrm *cstrm = NULL; struct zcomp_dstrm *dstrm; int ret; - cstrm = per_cpu_ptr(comp->cstream, cpu); - ret = zcomp_cstrm_init(comp, cstrm); - if (ret) { - pr_err("Can't allocate a compression stream\n"); - return ret; + if (comp->cstream) { + cstrm = per_cpu_ptr(comp->cstream, cpu); + ret = zcomp_cstrm_init(comp, cstrm); + if (ret) { + pr_err("Can't allocate a compression stream\n"); + return ret; + } } dstrm = per_cpu_ptr(comp->dstream, cpu); ret = zcomp_dstrm_init(comp, dstrm); if (ret) { pr_err("Can't allocate a decompression stream\n"); - zcomp_cstrm_free(comp, cstrm); + if (cstrm) + zcomp_cstrm_free(comp, cstrm); return ret; } @@ -354,10 +362,12 @@ int zcomp_cpu_dead(unsigned int cpu, str struct zcomp_cstrm *cstrm; struct zcomp_dstrm *dstrm; - cstrm = per_cpu_ptr(comp->cstream, cpu); - mutex_lock(&cstrm->lock); - zcomp_cstrm_free(comp, cstrm); - mutex_unlock(&cstrm->lock); + if (comp->cstream) { + cstrm = per_cpu_ptr(comp->cstream, cpu); + mutex_lock(&cstrm->lock); + zcomp_cstrm_free(comp, cstrm); + mutex_unlock(&cstrm->lock); + } dstrm = per_cpu_ptr(comp->dstream, cpu); down_write(&dstrm->lock); @@ -367,7 +377,8 @@ int zcomp_cpu_dead(unsigned int cpu, str return 0; } -static int zcomp_init(struct zcomp *comp, struct zcomp_params *params) +static int zcomp_init(struct zcomp *comp, struct zcomp_params *params, + bool recomp) { int ret, cpu; @@ -376,10 +387,28 @@ static int zcomp_init(struct zcomp *comp if (ret) goto cleanup; - comp->cstream = alloc_percpu(struct zcomp_cstrm); - if (!comp->cstream) { - ret = -ENOMEM; - goto cleanup; + if (recomp) { + comp->recomp_cstream = kzalloc_obj(*comp->recomp_cstream); + if (!comp->recomp_cstream) { + ret = -ENOMEM; + goto cleanup; + } + mutex_init(&comp->recomp_cstream->lock); + ret = zcomp_cstrm_init(comp, comp->recomp_cstream); + if (ret) { + /* zcomp_cstrm_init() cleans up after itself */ + kfree(comp->recomp_cstream); + comp->recomp_cstream = NULL; + goto cleanup; + } + } else { + comp->cstream = alloc_percpu(struct zcomp_cstrm); + if (!comp->cstream) { + ret = -ENOMEM; + goto cleanup; + } + for_each_possible_cpu(cpu) + mutex_init(&per_cpu_ptr(comp->cstream, cpu)->lock); } comp->dstream = alloc_percpu(struct zcomp_dstrm); @@ -393,7 +422,6 @@ static int zcomp_init(struct zcomp *comp for_each_possible_cpu(cpu) { struct zcomp_dstrm *zstrm = per_cpu_ptr(comp->dstream, cpu); - mutex_init(&per_cpu_ptr(comp->cstream, cpu)->lock); init_rwsem(&zstrm->lock); mutex_init(&zstrm->excl_lock); } @@ -405,6 +433,10 @@ static int zcomp_init(struct zcomp *comp return 0; cleanup: + if (comp->recomp_cstream) { + zcomp_cstrm_free(comp, comp->recomp_cstream); + kfree(comp->recomp_cstream); + } comp->ops->release_params(comp->params); free_percpu(comp->dstream); free_percpu(comp->cstream); @@ -414,13 +446,18 @@ cleanup: void zcomp_destroy(struct zcomp *comp) { cpuhp_state_remove_instance(CPUHP_ZCOMP_PREPARE, &comp->node); + if (comp->recomp_cstream) { + zcomp_cstrm_free(comp, comp->recomp_cstream); + kfree(comp->recomp_cstream); + } comp->ops->release_params(comp->params); free_percpu(comp->dstream); free_percpu(comp->cstream); kfree(comp); } -struct zcomp *zcomp_create(const char *alg, struct zcomp_params *params) +struct zcomp *zcomp_create(const char *alg, struct zcomp_params *params, + bool recomp) { struct zcomp *comp; int error; @@ -443,7 +480,7 @@ struct zcomp *zcomp_create(const char *a return ERR_PTR(-EINVAL); } - error = zcomp_init(comp, params); + error = zcomp_init(comp, params, recomp); if (error) { kfree(comp); return ERR_PTR(error); --- a/drivers/block/zram/zcomp.h~zram-use-a-singleton-compression-context-for-recompression +++ a/drivers/block/zram/zcomp.h @@ -40,7 +40,8 @@ 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 (except for recompression, which uses a single + * per-device compression stream). */ struct zcomp_ctx { void *context; @@ -95,9 +96,10 @@ struct zcomp_ops { /* dynamic per-device compression frontend */ struct zcomp { - struct zcomp_cstrm __percpu *cstream; struct zcomp_dstrm __percpu *dstream; wait_queue_head_t dstrm_waitq; + struct zcomp_cstrm __percpu *cstream; + struct zcomp_cstrm *recomp_cstream; const struct zcomp_ops *ops; struct zcomp_params *params; struct hlist_node node; @@ -108,7 +110,8 @@ int zcomp_cpu_dead(unsigned int cpu, str ssize_t zcomp_available_show(const char *comp, char *buf, ssize_t at); const char *zcomp_lookup_backend_name(const char *comp); -struct zcomp *zcomp_create(const char *alg, struct zcomp_params *params); +struct zcomp *zcomp_create(const char *alg, struct zcomp_params *params, + bool recomp); void zcomp_destroy(struct zcomp *comp); struct zcomp_cstrm *zcomp_cstrm_get(struct zcomp *comp); --- a/drivers/block/zram/zram_drv.c~zram-use-a-singleton-compression-context-for-recompression +++ a/drivers/block/zram/zram_drv.c @@ -2526,7 +2526,7 @@ static int recompress_slot(struct zram * } /* - * We are holding per-CPU stream mutex and entry lock so better + * We are holding compression stream mutex and entry lock so better * avoid direct reclaim. Allocation error is not fatal since * we still have the old object in the mem_pool. * @@ -2920,7 +2920,8 @@ static ssize_t disksize_store(struct dev continue; comp = zcomp_create(zram->comp_algs[prio], - &zram->params[prio]); + &zram->params[prio], + prio != ZRAM_PRIMARY_COMP); if (IS_ERR(comp)) { pr_err("Cannot initialise %s compressing backend\n", zram->comp_algs[prio]); _ Patches currently in -mm which might be from senozhatsky@chromium.org are zram-prefix-backends-printk-s.patch zram-remove-debugfs-entry-on-init-failure.patch zram-reset-writeback-state-in-zram_reset_device.patch zram-move-mark_slot_accessed-under-existing-slot-lock-sections.patch zram-remove-stale-warn_on-from-zram_read_page.patch zram-zstd-do-not-allocate-empty-c-d-dictionaries.patch zram-lz4hc-pre-initialize-dictionary-stream-in-setup_params.patch zram-lz4-use-lz4_decompress_safe_usingdict.patch zram-lz4hc-use-lz4_decompress_safe_usingdict.patch zram-zstd-do-not-use-kvzalloc-for-zstd-allocations.patch zram-split-zcomp-into-separate-r-w-streams.patch zram-introduce-shared-decompression-streams.patch zram-allocate-bounce-buffer-for-spanning-objects.patch zram-borrow-idle-decompression-streams-in-exclusive-mode.patch zram-use-a-singleton-compression-context-for-recompression.patch