Skip to content

Commit fc06121

Browse files
Richard Changkawasaki
authored andcommitted
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 <[email protected]>
1 parent 8e8e520 commit fc06121

File tree

3 files changed

+140
-0
lines changed

3 files changed

+140
-0
lines changed

drivers/block/zram/zram_drv.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2871,6 +2871,9 @@ static int __init zram_init(void)
28712871
num_devices--;
28722872
}
28732873

2874+
if (setup_zram_writeback())
2875+
goto out_error;
2876+
28742877
return 0;
28752878

28762879
out_error:
@@ -2880,6 +2883,7 @@ static int __init zram_init(void)
28802883

28812884
static void __exit zram_exit(void)
28822885
{
2886+
destroy_zram_writeback();
28832887
destroy_devices();
28842888
}
28852889

drivers/block/zram/zram_wb.c

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,16 @@
55

66
#include <linux/module.h>
77
#include <linux/kernel.h>
8+
#include <linux/kthread.h>
9+
#include <linux/wait.h>
10+
#include <linux/freezer.h>
811

912
#include "zram_wb.h"
1013

14+
static struct task_struct *wb_thread;
15+
static DECLARE_WAIT_QUEUE_HEAD(wb_wq);
16+
static struct zram_wb_request_list wb_req_list;
17+
1118
unsigned long alloc_block_bdev(struct zram *zram)
1219
{
1320
unsigned long blk_idx = 1;
@@ -33,3 +40,110 @@ void free_block_bdev(struct zram *zram, unsigned long blk_idx)
3340
atomic64_dec(&zram->stats.bd_count);
3441
}
3542

43+
static void complete_wb_request(struct zram_wb_request *req)
44+
{
45+
struct zram *zram = req->zram;
46+
unsigned long blk_idx = req->blk_idx;
47+
48+
free_block_bdev(zram, blk_idx);
49+
free_wb_request(req);
50+
}
51+
52+
void enqueue_wb_request(struct zram_wb_request_list *req_list,
53+
struct zram_wb_request *req)
54+
{
55+
spin_lock_bh(&req_list->lock);
56+
list_add_tail(&req->node, &req_list->head);
57+
req_list->count++;
58+
spin_unlock_bh(&req_list->lock);
59+
}
60+
61+
static struct zram_wb_request *dequeue_wb_request(
62+
struct zram_wb_request_list *req_list)
63+
{
64+
struct zram_wb_request *req = NULL;
65+
66+
spin_lock_bh(&req_list->lock);
67+
if (!list_empty(&req_list->head)) {
68+
req = list_first_entry(&req_list->head,
69+
struct zram_wb_request,
70+
node);
71+
list_del(&req->node);
72+
req_list->count--;
73+
}
74+
spin_unlock_bh(&req_list->lock);
75+
76+
return req;
77+
}
78+
79+
static void destroy_wb_request_list(struct zram_wb_request_list *req_list)
80+
{
81+
struct zram_wb_request *req;
82+
83+
while (!list_empty(&req_list->head)) {
84+
req = dequeue_wb_request(req_list);
85+
free_block_bdev(req->zram, req->blk_idx);
86+
free_wb_request(req);
87+
}
88+
}
89+
90+
static bool wb_ready_to_run(void)
91+
{
92+
int count;
93+
94+
spin_lock_bh(&wb_req_list.lock);
95+
count = wb_req_list.count;
96+
spin_unlock_bh(&wb_req_list.lock);
97+
98+
return count > 0;
99+
}
100+
101+
static int wb_thread_func(void *data)
102+
{
103+
set_freezable();
104+
105+
while (!kthread_should_stop()) {
106+
wait_event_freezable(wb_wq, wb_ready_to_run());
107+
108+
while (1) {
109+
struct zram_wb_request *req;
110+
111+
req = dequeue_wb_request(&wb_req_list);
112+
if (!req)
113+
break;
114+
complete_wb_request(req);
115+
}
116+
}
117+
return 0;
118+
}
119+
120+
void free_wb_request(struct zram_wb_request *req)
121+
{
122+
struct bio *bio = req->bio;
123+
struct page *page = bio_first_page_all(bio);
124+
125+
__free_page(page);
126+
bio_put(bio);
127+
kfree(req);
128+
}
129+
130+
int setup_zram_writeback(void)
131+
{
132+
spin_lock_init(&wb_req_list.lock);
133+
INIT_LIST_HEAD(&wb_req_list.head);
134+
wb_req_list.count = 0;
135+
136+
wb_thread = kthread_run(wb_thread_func, NULL, "zram_wb_thread");
137+
if (IS_ERR(wb_thread)) {
138+
pr_err("Unable to create zram_wb_thread\n");
139+
return -1;
140+
}
141+
return 0;
142+
}
143+
144+
void destroy_zram_writeback(void)
145+
{
146+
kthread_stop(wb_thread);
147+
destroy_wb_request_list(&wb_req_list);
148+
}
149+

drivers/block/zram/zram_wb.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,34 @@
66
#include <linux/bio.h>
77
#include "zram_drv.h"
88

9+
struct zram_wb_request {
10+
struct zram *zram;
11+
unsigned long blk_idx;
12+
struct zram_pp_slot *pps;
13+
struct zram_pp_ctl *ppctl;
14+
struct bio *bio;
15+
struct list_head node;
16+
};
17+
18+
struct zram_wb_request_list {
19+
struct list_head head;
20+
int count;
21+
spinlock_t lock;
22+
};
23+
924
#if IS_ENABLED(CONFIG_ZRAM_WRITEBACK)
1025
unsigned long alloc_block_bdev(struct zram *zram);
1126
void free_block_bdev(struct zram *zram, unsigned long blk_idx);
27+
int setup_zram_writeback(void);
28+
void destroy_zram_writeback(void);
29+
void free_wb_request(struct zram_wb_request *req);
30+
void enqueue_wb_request(struct zram_wb_request_list *req_list,
31+
struct zram_wb_request *req);
1232
#else
1333
inline unsigned long alloc_block_bdev(struct zram *zram) { return 0; }
1434
inline void free_block_bdev(struct zram *zram, unsigned long blk_idx) {};
35+
inline int setup_zram_writeback(void) { return 0; }
36+
inline void destroy_zram_writeback(void) {}
1537
#endif
1638

1739
#endif /* _ZRAM_WRITEBACK_H_ */

0 commit comments

Comments
 (0)