[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250731064949.1690732-3-richardycc@google.com>
Date: Thu, 31 Jul 2025 06:49:48 +0000
From: Richard Chang <richardycc@...gle.com>
To: Minchan Kim <minchan@...nel.org>, Sergey Senozhatsky <senozhatsky@...omium.org>,
Jens Axboe <axboe@...nel.dk>, Andrew Morton <akpm@...ux-foundation.org>
Cc: bgeffon@...gle.com, liumartin@...gle.com, linux-kernel@...r.kernel.org,
linux-block@...r.kernel.org, linux-mm@...ck.org,
Richard Chang <richardycc@...gle.com>
Subject: [PATCH v2 2/3] zram: add async writeback infrastructure
Introduce the necessary infrastructure for performing writeback
operations asynchronously.
It adds a dedicated kernel thread (`zram_wb_thread`), a request queue
for managing pending writebacks, and helper functions to deal with
the writeback requests.
This patch lays the foundation for enabling asynchronous writeback in a
subsequent change.
Signed-off-by: Richard Chang <richardycc@...gle.com>
---
drivers/block/zram/zram_drv.c | 4 ++
drivers/block/zram/zram_wb.c | 114 ++++++++++++++++++++++++++++++++++
drivers/block/zram/zram_wb.h | 22 +++++++
3 files changed, 140 insertions(+)
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index ec8649cad21e..6098c0bb773c 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -2871,6 +2871,9 @@ static int __init zram_init(void)
num_devices--;
}
+ if (setup_zram_writeback())
+ goto out_error;
+
return 0;
out_error:
@@ -2880,6 +2883,7 @@ static int __init zram_init(void)
static void __exit zram_exit(void)
{
+ destroy_zram_writeback();
destroy_devices();
}
diff --git a/drivers/block/zram/zram_wb.c b/drivers/block/zram/zram_wb.c
index 0bc10f725939..63a16dae5796 100644
--- a/drivers/block/zram/zram_wb.c
+++ b/drivers/block/zram/zram_wb.c
@@ -5,9 +5,16 @@
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/freezer.h>
#include "zram_wb.h"
+static struct task_struct *wb_thread;
+static DECLARE_WAIT_QUEUE_HEAD(wb_wq);
+static struct zram_wb_request_list wb_req_list;
+
unsigned long alloc_block_bdev(struct zram *zram)
{
unsigned long blk_idx = 1;
@@ -33,3 +40,110 @@ void free_block_bdev(struct zram *zram, unsigned long blk_idx)
atomic64_dec(&zram->stats.bd_count);
}
+static void complete_wb_request(struct zram_wb_request *req)
+{
+ struct zram *zram = req->zram;
+ unsigned long blk_idx = req->blk_idx;
+
+ free_block_bdev(zram, blk_idx);
+ free_wb_request(req);
+}
+
+void enqueue_wb_request(struct zram_wb_request_list *req_list,
+ struct zram_wb_request *req)
+{
+ spin_lock_bh(&req_list->lock);
+ list_add_tail(&req->node, &req_list->head);
+ req_list->count++;
+ spin_unlock_bh(&req_list->lock);
+}
+
+static struct zram_wb_request *dequeue_wb_request(
+ struct zram_wb_request_list *req_list)
+{
+ struct zram_wb_request *req = NULL;
+
+ spin_lock_bh(&req_list->lock);
+ if (!list_empty(&req_list->head)) {
+ req = list_first_entry(&req_list->head,
+ struct zram_wb_request,
+ node);
+ list_del(&req->node);
+ req_list->count--;
+ }
+ spin_unlock_bh(&req_list->lock);
+
+ return req;
+}
+
+static void destroy_wb_request_list(struct zram_wb_request_list *req_list)
+{
+ struct zram_wb_request *req;
+
+ while (!list_empty(&req_list->head)) {
+ req = dequeue_wb_request(req_list);
+ free_block_bdev(req->zram, req->blk_idx);
+ free_wb_request(req);
+ }
+}
+
+static bool wb_ready_to_run(void)
+{
+ int count;
+
+ spin_lock_bh(&wb_req_list.lock);
+ count = wb_req_list.count;
+ spin_unlock_bh(&wb_req_list.lock);
+
+ return count > 0;
+}
+
+static int wb_thread_func(void *data)
+{
+ set_freezable();
+
+ while (!kthread_should_stop()) {
+ wait_event_freezable(wb_wq, wb_ready_to_run());
+
+ while (1) {
+ struct zram_wb_request *req;
+
+ req = dequeue_wb_request(&wb_req_list);
+ if (!req)
+ break;
+ complete_wb_request(req);
+ }
+ }
+ return 0;
+}
+
+void free_wb_request(struct zram_wb_request *req)
+{
+ struct bio *bio = req->bio;
+ struct page *page = bio_first_page_all(bio);
+
+ __free_page(page);
+ bio_put(bio);
+ kfree(req);
+}
+
+int setup_zram_writeback(void)
+{
+ spin_lock_init(&wb_req_list.lock);
+ INIT_LIST_HEAD(&wb_req_list.head);
+ wb_req_list.count = 0;
+
+ wb_thread = kthread_run(wb_thread_func, NULL, "zram_wb_thread");
+ if (IS_ERR(wb_thread)) {
+ pr_err("Unable to create zram_wb_thread\n");
+ return -1;
+ }
+ return 0;
+}
+
+void destroy_zram_writeback(void)
+{
+ kthread_stop(wb_thread);
+ destroy_wb_request_list(&wb_req_list);
+}
+
diff --git a/drivers/block/zram/zram_wb.h b/drivers/block/zram/zram_wb.h
index c2f5984e7aa2..b86de0398346 100644
--- a/drivers/block/zram/zram_wb.h
+++ b/drivers/block/zram/zram_wb.h
@@ -6,12 +6,34 @@
#include <linux/bio.h>
#include "zram_drv.h"
+struct zram_wb_request {
+ struct zram *zram;
+ unsigned long blk_idx;
+ struct zram_pp_slot *pps;
+ struct zram_pp_ctl *ppctl;
+ struct bio *bio;
+ struct list_head node;
+};
+
+struct zram_wb_request_list {
+ struct list_head head;
+ int count;
+ spinlock_t lock;
+};
+
#if IS_ENABLED(CONFIG_ZRAM_WRITEBACK)
unsigned long alloc_block_bdev(struct zram *zram);
void free_block_bdev(struct zram *zram, unsigned long blk_idx);
+int setup_zram_writeback(void);
+void destroy_zram_writeback(void);
+void free_wb_request(struct zram_wb_request *req);
+void enqueue_wb_request(struct zram_wb_request_list *req_list,
+ struct zram_wb_request *req);
#else
inline unsigned long alloc_block_bdev(struct zram *zram) { return 0; }
inline void free_block_bdev(struct zram *zram, unsigned long blk_idx) {};
+inline int setup_zram_writeback(void) { return 0; }
+inline void destroy_zram_writeback(void) {}
#endif
#endif /* _ZRAM_WRITEBACK_H_ */
--
2.50.1.565.gc32cd1483b-goog
Powered by blists - more mailing lists