From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 29E9AC19F32 for ; Fri, 7 Mar 2025 19:41:33 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 22E1A6B007B; Fri, 7 Mar 2025 14:41:30 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 1DD4F6B0082; Fri, 7 Mar 2025 14:41:30 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 057AC6B0083; Fri, 7 Mar 2025 14:41:29 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0016.hostedemail.com [216.40.44.16]) by kanga.kvack.org (Postfix) with ESMTP id D6D306B007B for ; Fri, 7 Mar 2025 14:41:29 -0500 (EST) Received: from smtpin12.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay06.hostedemail.com (Postfix) with ESMTP id 6BCD6B8228 for ; Fri, 7 Mar 2025 19:41:31 +0000 (UTC) X-FDA: 83195774382.12.1D1486C Received: from mail-ua1-f47.google.com (mail-ua1-f47.google.com [209.85.222.47]) by imf02.hostedemail.com (Postfix) with ESMTP id 718988000D for ; Fri, 7 Mar 2025 19:41:29 +0000 (UTC) Authentication-Results: imf02.hostedemail.com; dkim=pass header.d=gmail.com header.s=20230601 header.b=GkyzHt6p; dmarc=pass (policy=none) header.from=gmail.com; spf=pass (imf02.hostedemail.com: domain of 21cnbao@gmail.com designates 209.85.222.47 as permitted sender) smtp.mailfrom=21cnbao@gmail.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1741376489; a=rsa-sha256; cv=none; b=UXlL5SAeOc+wUd++BYWQUSSJSyUZRdu2HgXhwupwyBPl4hxUpOtf3So72u37TOIuaKyPpu lVqfQWpteceG+soX24HfjXw7kaAto2kwhB5DBIe9hWJ5uNurt/qsKix5v0AU0q0ukSTTtq sTn2T6PrWJVdQtnyu2xMzrEHIRieNXE= ARC-Authentication-Results: i=1; imf02.hostedemail.com; dkim=pass header.d=gmail.com header.s=20230601 header.b=GkyzHt6p; dmarc=pass (policy=none) header.from=gmail.com; spf=pass (imf02.hostedemail.com: domain of 21cnbao@gmail.com designates 209.85.222.47 as permitted sender) smtp.mailfrom=21cnbao@gmail.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1741376489; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=mxADRnTRL5Zf4OanqbxnTYyjpNbUObusM/RVQfon6dU=; b=fLdn4iFLR8RzePQOn+mE7B1ZGLVu3hVjxB4kIXh2+JMCegZ/aurzmkm5lQnIKYKbiZr+/R k6C/iVKATOuEURBG6pFixH2dLSzHmfcRNMfst0bC9Tn2prxYWAzJ+I+4tqij7CV/g9+tUK wUax1tV2vSx9fqpNB35NZ41eX0L0hZo= Received: by mail-ua1-f47.google.com with SMTP id a1e0cc1a2514c-86b68e51af4so845389241.1 for ; Fri, 07 Mar 2025 11:41:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1741376488; x=1741981288; darn=kvack.org; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=mxADRnTRL5Zf4OanqbxnTYyjpNbUObusM/RVQfon6dU=; b=GkyzHt6pEpXApgrwdZv3sgrsyqyzrCkfSC36w2FxcqCynbBGf9u8hduTYTgbEBujM3 XNVD3CMdXY3JHQ27LIiHtAzT9JkRTce37A/gFG0Xh+0pXOapveCSxjw88xNVPmQsnahX u+W9Dl9IfPE9hZGq023/wPZATd3K2+LTNZ+y2OtRSrVdbcpL3XM/9JCcI47lcPGuRFs3 dPg40t7nBfsMjJ0jv1cu7AkTm2t6lVdPcpmJU1PnKUzWXqL7mF4negzKQdhjtKVfO4HV WKB3wf2w6U9jZ3h85+00vEwPBxYMlGBTPEANr3cvXbOjFx+YIDGNJAsChYc3sPMpVZxd TN4w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741376488; x=1741981288; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=mxADRnTRL5Zf4OanqbxnTYyjpNbUObusM/RVQfon6dU=; b=CXEOSdQ4fiTdrNhfg6Vb7HBpSLCZZRl85+AvkMw7Iptx7FIj3TAvfY9WFzF4TDpIeq db7TUUEp/WqVWq9Qj7RNe04MOpcgcO7EN2otZXRKQmD/s8gSEWRCjGg/3gdeRSZA6JUT BaN5adnFFXb/IaQvL8gsbSULmlkyMzQGvR7qZspVlhcVE/o7pP49pmA4MGzJiANbPGNo g1TvX4eZqv993kTslwKI9Fr2XaueINUyALuLKw32C/qPq1bk4coL13vMbLhGIY5BeCOk n8cyH2wfcBxauIJxB8DQU5176yQB1zjG6XSyCi5lXlPbA6UnZsPmKTIqQbexEKs0e7iD X07w== X-Forwarded-Encrypted: i=1; AJvYcCVjWtydyymzRjSsf+RNMmTEcxeOKZ9MxGbg96C4IvEueto5/rSYwoTToBd39Ioly76cM78Gn0XxhA==@kvack.org X-Gm-Message-State: AOJu0YxF7WQPCXqyeF1GdlkhZPXijmZU9AMgYcKvvRb2RJurGJlDluG+ Drb+zhFrWqMxCxGxtDZp9Z1vg+rtLGXoTe3pKipYBYXmF1H3jIOmiALaSJWxudR4EGFo3NVwj8n qWzBDiUUDzgZN7utFpq5rbKsTJDU= X-Gm-Gg: ASbGncsty9XRkSCmGJ6oddfbVaoJsXeqU9qTLHpa9pQeFDPd3PCpt4BJqZXTNClMTRz 1Phdm8iwnbrAblZWaws6fDZ36tIP2DlzCEz69h1bY9p3/eRzIEjB5hw/6qHon1onTiZuyV71eO0 cOf/7Fm7M9y442sWvddYHt2y5Afg== X-Google-Smtp-Source: AGHT+IErC9InPZ9XBRKp6Rom58kBjYYUxu3mePp0BMBXU1RuaBhOiaC4Tj1uk5RWPM1jNhqDuhDOHzIrZjJrW7wbKg4= X-Received: by 2002:a05:6102:d8e:b0:4c1:a448:ac7d with SMTP id ada2fe7eead31-4c30a54d408mr3032359137.10.1741376488483; Fri, 07 Mar 2025 11:41:28 -0800 (PST) MIME-Version: 1.0 References: <20250307120141.1566673-1-qun-wei.lin@mediatek.com> <20250307120141.1566673-3-qun-wei.lin@mediatek.com> In-Reply-To: <20250307120141.1566673-3-qun-wei.lin@mediatek.com> From: Barry Song <21cnbao@gmail.com> Date: Sat, 8 Mar 2025 08:41:17 +1300 X-Gm-Features: AQ5f1Jr_NH_JmxbOO5LScfPMgZlBxT61u6xunECHMLc6vlHdXZJRYzFSi8sd-ig Message-ID: Subject: Re: [PATCH 2/2] kcompressd: Add Kcompressd for accelerated zram compression To: Qun-Wei Lin Cc: Jens Axboe , Minchan Kim , Sergey Senozhatsky , Vishal Verma , Dan Williams , Dave Jiang , Ira Weiny , Andrew Morton , Matthias Brugger , AngeloGioacchino Del Regno , Chris Li , Ryan Roberts , "Huang, Ying" , Kairui Song , Dan Schatzberg , Al Viro , linux-kernel@vger.kernel.org, linux-block@vger.kernel.org, nvdimm@lists.linux.dev, linux-mm@kvack.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, Casper Li , Chinwen Chang , Andrew Yang , James Hsu Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Rspamd-Queue-Id: 718988000D X-Rspamd-Server: rspam11 X-Stat-Signature: bgcz468y3rg3x6ia4kdweygrbwqycbd7 X-Rspam-User: X-HE-Tag: 1741376489-166629 X-HE-Meta: U2FsdGVkX1+27hWkJepHIAcJuAMgegP1ApPnFAnBsInnWuOhKbSH668VxcDki7QsEHMB1oL+IIpjHbPegDVRFygf6Qen592trAXa373qP10z/GVrtI7XnWdq+rBj5antRnf1nIksPHRaIsADj8dU9O2wxTI4W4sTgtDvtGa/N2sT9PFcS3vIdO4ivphdjn98nTtw596h1Ap+GHwla4UsmsFHmdRdqvmbT/I1bP4LjIg9dR+b4NZVWWXrFacdhOcIRcOOXz2dbliwfafbT8No+PYRg57UUKEAa/Sm7jXcuPQVrUCXUlOgmO/nqCuTSuSFcQNzvAfU+wykHAivjT2mAenkhyi1EfToFozclXQa8YklS57lN5JIoMNJiFtEMQz8V6mwTUvxoGy27aSh4FhZERGR2nCf27p01oiWcCdruEPQmW6Q9gNMSDAkzwTmaA2a2OPWQYLos6XPmHpb7Dq2MlsV4piP+Z99A4R07Y5G3rYut22IN4NoPJkeCzwUjOXwr5GEwFxHtBFcYGf1HFE+5J6867THPBS5olEq2G+mpcgMaAguFQ9WRk+Wd/LaXW0i9YKs4TR1C1jKHMchOEEKEnjU+4gCrcr9gLoVhZjXDmrOgwNP3dSF6sAmdN+xKfHWBCqCet/yYlI3mVyOYj0ukiAqPVWgli63BqKFo7orL1wVE+2icGzuZvbLxVH1j3n7X7bJJeugxmnqvyOEgc8BnZCPjFaqhMULki8rIpDU6hg5Sc0fKt5F1UbKjMuabTji2Et95qgPkoVh0shwwQDL+UZ07BV9bnydqHBosQ0GbkBKcCRxwlo9K5rJChXdvYR+BvaN6Iv61sqxfSamdOEmf+aGfedjWeuWEz9yqtX5GpJDmztQ2aSvKt8SYL+eZLCbPathOQCJ+MRs289EuBlGHNpWFuMIf4R5D3lsKhNvJ7jTnkyFFWIjoejl1KwXEDJm53sNDhZGimk110xvjID zwoWQ/JE QpKTP7L7MB8VpsN+AmwPl9h6DQXEmlHP1AzyFpGSJTUJxtfJytWEnWij1vI7ajQI96UnZUlXIYcNUI6prbLDn5vreYHRcL7SyzgmsfC9JhKJ56lLyQykuMPdJXSOAOgN5p7Vlx2jrpcmSibdlS99IJyog852eZqtnVViPTCjTocop21QIbzxi7DLWLIdLT+rVI456AXmzceEaXvNbNeXqGaWA6d07YuwX5h4jj+NNFQBgAA0dzoF71NsqQ5bbhKRakYpG/a+C99ll6pGue8Q6k1XFAcHM6qUKLqzP/Yw5WOjM1A7//hY+p1WWG9Vx1p2f955oct8sLovwHC2E4Nf7KFkfZqYdEGgk1IMb1v7Vh19JADZn/jkKE72TXYK1c+dnJHlpu/yYuZ10MCiC8cG0pK3MDzvVxOwwxxnT X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: On Sat, Mar 8, 2025 at 1:02=E2=80=AFAM Qun-Wei Lin wrote: > > Introduced Kcompressd to offload zram page compression, improving > system efficiency by handling compression separately from memory > reclaiming. Added necessary configurations and dependencies. > > Signed-off-by: Qun-Wei Lin > --- > drivers/block/zram/Kconfig | 11 ++ > drivers/block/zram/Makefile | 3 +- > drivers/block/zram/kcompressd.c | 340 ++++++++++++++++++++++++++++++++ > drivers/block/zram/kcompressd.h | 25 +++ > drivers/block/zram/zram_drv.c | 22 ++- > 5 files changed, 397 insertions(+), 4 deletions(-) > create mode 100644 drivers/block/zram/kcompressd.c > create mode 100644 drivers/block/zram/kcompressd.h > > diff --git a/drivers/block/zram/Kconfig b/drivers/block/zram/Kconfig > index 402b7b175863..f0a1b574f770 100644 > --- a/drivers/block/zram/Kconfig > +++ b/drivers/block/zram/Kconfig > @@ -145,3 +145,14 @@ config ZRAM_MULTI_COMP > re-compress pages using a potentially slower but more effective > compression algorithm. Note, that IDLE page recompression > requires ZRAM_TRACK_ENTRY_ACTIME. > + > +config KCOMPRESSD > + tristate "Kcompressd: Accelerated zram compression" > + depends on ZRAM > + help > + Kcompressd creates multiple daemons to accelerate the compressi= on of pages > + in zram, offloading this time-consuming task from the zram driv= er. > + > + This approach improves system efficiency by handling page compr= ession separately, > + which was originally done by kswapd or direct reclaim. For direct reclaim, we were previously able to compress using multiple CPUs with multi-threading. After your patch, it seems that only a single thread/CPU is used for compre= ssion so it won't necessarily improve direct reclaim performance? Even for kswapd, we used to have multiple threads like [kswapd0], [kswapd1]= , and [kswapd2] for different nodes. Now, are we also limited to just one thr= ead? I also wonder if this could be handled at the vmscan level instead of the z= ram level. then it might potentially help other sync devices or even zswap late= r. But I agree that for phones, modifying zram seems like an easier starting point. However, relying on a single thread isn't always the best approach. > + > diff --git a/drivers/block/zram/Makefile b/drivers/block/zram/Makefile > index 0fdefd576691..23baa5dfceb9 100644 > --- a/drivers/block/zram/Makefile > +++ b/drivers/block/zram/Makefile > @@ -9,4 +9,5 @@ zram-$(CONFIG_ZRAM_BACKEND_ZSTD) +=3D backend_zstd= .o > zram-$(CONFIG_ZRAM_BACKEND_DEFLATE) +=3D backend_deflate.o > zram-$(CONFIG_ZRAM_BACKEND_842) +=3D backend_842.o > > -obj-$(CONFIG_ZRAM) +=3D zram.o > +obj-$(CONFIG_ZRAM) +=3D zram.o > +obj-$(CONFIG_KCOMPRESSD) +=3D kcompressd.o > diff --git a/drivers/block/zram/kcompressd.c b/drivers/block/zram/kcompre= ssd.c > new file mode 100644 > index 000000000000..195b7e386869 > --- /dev/null > +++ b/drivers/block/zram/kcompressd.c > @@ -0,0 +1,340 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (C) 2024 MediaTek Inc. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "kcompressd.h" > + > +#define INIT_QUEUE_SIZE 4096 > +#define DEFAULT_NR_KCOMPRESSD 4 > + > +static atomic_t enable_kcompressd; > +static unsigned int nr_kcompressd; > +static unsigned int queue_size_per_kcompressd; > +static struct kcompress *kcompress; > + > +enum run_state { > + KCOMPRESSD_NOT_STARTED =3D 0, > + KCOMPRESSD_RUNNING, > + KCOMPRESSD_SLEEPING, > +}; > + > +struct kcompressd_para { > + wait_queue_head_t *kcompressd_wait; > + struct kfifo *write_fifo; > + atomic_t *running; > +}; > + > +static struct kcompressd_para *kcompressd_para; > +static BLOCKING_NOTIFIER_HEAD(kcompressd_notifier_list); > + > +struct write_work { > + void *mem; > + struct bio *bio; > + compress_callback cb; > +}; > + > +int kcompressd_enabled(void) > +{ > + return likely(atomic_read(&enable_kcompressd)); > +} > +EXPORT_SYMBOL(kcompressd_enabled); > + > +static void kcompressd_try_to_sleep(struct kcompressd_para *p) > +{ > + DEFINE_WAIT(wait); > + > + if (!kfifo_is_empty(p->write_fifo)) > + return; > + > + if (freezing(current) || kthread_should_stop()) > + return; > + > + atomic_set(p->running, KCOMPRESSD_SLEEPING); > + prepare_to_wait(p->kcompressd_wait, &wait, TASK_INTERRUPTIBLE); > + > + /* > + * After a short sleep, check if it was a premature sleep. If not= , then > + * go fully to sleep until explicitly woken up. > + */ > + if (!kthread_should_stop() && kfifo_is_empty(p->write_fifo)) > + schedule(); > + > + finish_wait(p->kcompressd_wait, &wait); > + atomic_set(p->running, KCOMPRESSD_RUNNING); > +} > + > +static int kcompressd(void *para) > +{ > + struct task_struct *tsk =3D current; > + struct kcompressd_para *p =3D (struct kcompressd_para *)para; > + > + tsk->flags |=3D PF_MEMALLOC | PF_KSWAPD; > + set_freezable(); > + > + while (!kthread_should_stop()) { > + bool ret; > + > + kcompressd_try_to_sleep(p); > + ret =3D try_to_freeze(); > + if (kthread_should_stop()) > + break; > + > + if (ret) > + continue; > + > + while (!kfifo_is_empty(p->write_fifo)) { > + struct write_work entry; > + > + if (sizeof(struct write_work) =3D=3D kfifo_out(p-= >write_fifo, > + &entry, sizeof(struct wri= te_work))) { > + entry.cb(entry.mem, entry.bio); > + bio_put(entry.bio); > + } > + } > + > + } > + > + tsk->flags &=3D ~(PF_MEMALLOC | PF_KSWAPD); > + atomic_set(p->running, KCOMPRESSD_NOT_STARTED); > + return 0; > +} > + > +static int init_write_queue(void) > +{ > + int i; > + unsigned int queue_len =3D queue_size_per_kcompressd * sizeof(str= uct write_work); > + > + for (i =3D 0; i < nr_kcompressd; i++) { > + if (kfifo_alloc(&kcompress[i].write_fifo, > + queue_len, GFP_KERNEL)) { > + pr_err("Failed to alloc kfifo %d\n", i); > + return -ENOMEM; > + } > + } > + return 0; > +} > + > +static void clean_bio_queue(int idx) > +{ > + struct write_work entry; > + > + while (sizeof(struct write_work) =3D=3D kfifo_out(&kcompress[idx]= .write_fifo, > + &entry, sizeof(struct write_work))) { > + bio_put(entry.bio); > + entry.cb(entry.mem, entry.bio); > + } > + kfifo_free(&kcompress[idx].write_fifo); > +} > + > +static int kcompress_update(void) > +{ > + int i; > + int ret; > + > + kcompress =3D kvmalloc_array(nr_kcompressd, sizeof(struct kcompre= ss), GFP_KERNEL); > + if (!kcompress) > + return -ENOMEM; > + > + kcompressd_para =3D kvmalloc_array(nr_kcompressd, sizeof(struct k= compressd_para), GFP_KERNEL); > + if (!kcompressd_para) > + return -ENOMEM; > + > + ret =3D init_write_queue(); > + if (ret) { > + pr_err("Initialization of writing to FIFOs failed!!\n"); > + return ret; > + } > + > + for (i =3D 0; i < nr_kcompressd; i++) { > + init_waitqueue_head(&kcompress[i].kcompressd_wait); > + kcompressd_para[i].kcompressd_wait =3D &kcompress[i].kcom= pressd_wait; > + kcompressd_para[i].write_fifo =3D &kcompress[i].write_fif= o; > + kcompressd_para[i].running =3D &kcompress[i].running; > + } > + > + return 0; > +} > + > +static void stop_all_kcompressd_thread(void) > +{ > + int i; > + > + for (i =3D 0; i < nr_kcompressd; i++) { > + kthread_stop(kcompress[i].kcompressd); > + kcompress[i].kcompressd =3D NULL; > + clean_bio_queue(i); > + } > +} > + > +static int do_nr_kcompressd_handler(const char *val, > + const struct kernel_param *kp) > +{ > + int ret; > + > + atomic_set(&enable_kcompressd, false); > + > + stop_all_kcompressd_thread(); > + > + ret =3D param_set_int(val, kp); > + if (!ret) { > + pr_err("Invalid number of kcompressd.\n"); > + return -EINVAL; > + } > + > + ret =3D init_write_queue(); > + if (ret) { > + pr_err("Initialization of writing to FIFOs failed!!\n"); > + return ret; > + } > + > + atomic_set(&enable_kcompressd, true); > + > + return 0; > +} > + > +static const struct kernel_param_ops param_ops_change_nr_kcompressd =3D = { > + .set =3D &do_nr_kcompressd_handler, > + .get =3D ¶m_get_uint, > + .free =3D NULL, > +}; > + > +module_param_cb(nr_kcompressd, ¶m_ops_change_nr_kcompressd, > + &nr_kcompressd, 0644); > +MODULE_PARM_DESC(nr_kcompressd, "Number of pre-created daemon for page c= ompression"); > + > +static int do_queue_size_per_kcompressd_handler(const char *val, > + const struct kernel_param *kp) > +{ > + int ret; > + > + atomic_set(&enable_kcompressd, false); > + > + stop_all_kcompressd_thread(); > + > + ret =3D param_set_int(val, kp); > + if (!ret) { > + pr_err("Invalid queue size for kcompressd.\n"); > + return -EINVAL; > + } > + > + ret =3D init_write_queue(); > + if (ret) { > + pr_err("Initialization of writing to FIFOs failed!!\n"); > + return ret; > + } > + > + pr_info("Queue size for kcompressd was changed: %d\n", queue_size= _per_kcompressd); > + > + atomic_set(&enable_kcompressd, true); > + return 0; > +} > + > +static const struct kernel_param_ops param_ops_change_queue_size_per_kco= mpressd =3D { > + .set =3D &do_queue_size_per_kcompressd_handler, > + .get =3D ¶m_get_uint, > + .free =3D NULL, > +}; > + > +module_param_cb(queue_size_per_kcompressd, ¶m_ops_change_queue_size_= per_kcompressd, > + &queue_size_per_kcompressd, 0644); > +MODULE_PARM_DESC(queue_size_per_kcompressd, > + "Size of queue for kcompressd"); > + > +int schedule_bio_write(void *mem, struct bio *bio, compress_callback cb) > +{ > + int i; > + bool submit_success =3D false; > + size_t sz_work =3D sizeof(struct write_work); > + > + struct write_work entry =3D { > + .mem =3D mem, > + .bio =3D bio, > + .cb =3D cb > + }; > + > + if (unlikely(!atomic_read(&enable_kcompressd))) > + return -EBUSY; > + > + if (!nr_kcompressd || !current_is_kswapd()) > + return -EBUSY; > + > + bio_get(bio); > + > + for (i =3D 0; i < nr_kcompressd; i++) { > + submit_success =3D > + (kfifo_avail(&kcompress[i].write_fifo) >=3D sz_wo= rk) && > + (sz_work =3D=3D kfifo_in(&kcompress[i].write_fifo= , &entry, sz_work)); > + > + if (submit_success) { > + switch (atomic_read(&kcompress[i].running)) { > + case KCOMPRESSD_NOT_STARTED: > + atomic_set(&kcompress[i].running, KCOMPRE= SSD_RUNNING); > + kcompress[i].kcompressd =3D kthread_run(k= compressd, > + &kcompressd_para[i], "kco= mpressd:%d", i); > + if (IS_ERR(kcompress[i].kcompressd)) { > + atomic_set(&kcompress[i].running,= KCOMPRESSD_NOT_STARTED); > + pr_warn("Failed to start kcompres= sd:%d\n", i); > + clean_bio_queue(i); > + } > + break; > + case KCOMPRESSD_RUNNING: > + break; > + case KCOMPRESSD_SLEEPING: > + wake_up_interruptible(&kcompress[i].kcomp= ressd_wait); > + break; > + } > + return 0; > + } > + } > + > + bio_put(bio); > + return -EBUSY; > +} > +EXPORT_SYMBOL(schedule_bio_write); > + > +static int __init kcompressd_init(void) > +{ > + int ret; > + > + nr_kcompressd =3D DEFAULT_NR_KCOMPRESSD; > + queue_size_per_kcompressd =3D INIT_QUEUE_SIZE; > + > + ret =3D kcompress_update(); > + if (ret) { > + pr_err("Init kcompressd failed!\n"); > + return ret; > + } > + > + atomic_set(&enable_kcompressd, true); > + blocking_notifier_call_chain(&kcompressd_notifier_list, 0, NULL); > + return 0; > +} > + > +static void __exit kcompressd_exit(void) > +{ > + atomic_set(&enable_kcompressd, false); > + stop_all_kcompressd_thread(); > + > + kvfree(kcompress); > + kvfree(kcompressd_para); > +} > + > +module_init(kcompressd_init); > +module_exit(kcompressd_exit); > + > +MODULE_LICENSE("Dual BSD/GPL"); > +MODULE_AUTHOR("Qun-Wei Lin "); > +MODULE_DESCRIPTION("Separate the page compression from the memory reclai= ming"); > + > diff --git a/drivers/block/zram/kcompressd.h b/drivers/block/zram/kcompre= ssd.h > new file mode 100644 > index 000000000000..2fe0b424a7af > --- /dev/null > +++ b/drivers/block/zram/kcompressd.h > @@ -0,0 +1,25 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (C) 2024 MediaTek Inc. > + */ > + > +#ifndef _KCOMPRESSD_H_ > +#define _KCOMPRESSD_H_ > + > +#include > +#include > +#include > + > +typedef void (*compress_callback)(void *mem, struct bio *bio); > + > +struct kcompress { > + struct task_struct *kcompressd; > + wait_queue_head_t kcompressd_wait; > + struct kfifo write_fifo; > + atomic_t running; > +}; > + > +int kcompressd_enabled(void); > +int schedule_bio_write(void *mem, struct bio *bio, compress_callback cb)= ; > +#endif > + > diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.= c > index 2e1a70f2f4bd..bcd63ecb6ff2 100644 > --- a/drivers/block/zram/zram_drv.c > +++ b/drivers/block/zram/zram_drv.c > @@ -35,6 +35,7 @@ > #include > #include > > +#include "kcompressd.h" > #include "zram_drv.h" > > static DEFINE_IDR(zram_index_idr); > @@ -2240,6 +2241,15 @@ static void zram_bio_write(struct zram *zram, stru= ct bio *bio) > bio_endio(bio); > } > > +#if IS_ENABLED(CONFIG_KCOMPRESSD) > +static void zram_bio_write_callback(void *mem, struct bio *bio) > +{ > + struct zram *zram =3D (struct zram *)mem; > + > + zram_bio_write(zram, bio); > +} > +#endif > + > /* > * Handler function for all zram I/O requests. > */ > @@ -2252,6 +2262,10 @@ static void zram_submit_bio(struct bio *bio) > zram_bio_read(zram, bio); > break; > case REQ_OP_WRITE: > +#if IS_ENABLED(CONFIG_KCOMPRESSD) > + if (kcompressd_enabled() && !schedule_bio_write(zram, bio= , zram_bio_write_callback)) > + break; > +#endif > zram_bio_write(zram, bio); > break; > case REQ_OP_DISCARD: > @@ -2535,9 +2549,11 @@ static int zram_add(void) > #if ZRAM_LOGICAL_BLOCK_SIZE =3D=3D PAGE_SIZE > .max_write_zeroes_sectors =3D UINT_MAX, > #endif > - .features =3D BLK_FEAT_STABLE_WRITE= S | > - BLK_FEAT_READ_SYNCHRONO= US | > - BLK_FEAT_WRITE_SYNCHRON= OUS, > + .features =3D BLK_FEAT_STABLE_WRITE= S > + | BLK_FEAT_READ_SYNCHRO= NOUS > +#if !IS_ENABLED(CONFIG_KCOMPRESSD) > + | BLK_FEAT_WRITE_SYNCHR= ONOUS, > +#endif > }; > struct zram *zram; > int ret, device_id; > -- > 2.45.2 > Thanks Barry