1 |
From 7a5241523321fa6c67b8c17899ebfaf661db14e6 Mon Sep 17 00:00:00 2001 |
2 |
From: Thomas Backlund <tmb@mageia.org> |
3 |
Date: Wed, 10 Aug 2022 22:11:21 +0300 |
4 |
Subject: [PATCH] Revert "zram: remove double compression logic" |
5 |
|
6 |
This reverts commit e7be8d1dd983156bbdd22c0319b71119a8fbb697 as it |
7 |
causes zram failures. It does not revert cleanly, PTR_ERR handling was |
8 |
introduced in the meantime. This is handled by appropriate IS_ERR. |
9 |
|
10 |
When under memory pressure, zs_malloc() can fail. Before the above |
11 |
commit, the allocation was retried with direct reclaim enabled |
12 |
(GFP_NOIO). After the commit, it is not -- only __GFP_KSWAPD_RECLAIM is |
13 |
tried. |
14 |
|
15 |
So when the failure occurs under memory pressure, the overlaying |
16 |
filesystem such as ext2 (mounted by ext4 module in this case) can emit |
17 |
failures, making the (file)system unusable: |
18 |
EXT4-fs warning (device zram0): ext4_end_bio:343: I/O error 10 writing to inode 16386 starting block 159744) |
19 |
Buffer I/O error on device zram0, logical block 159744 |
20 |
|
21 |
With direct reclaim, memory is really reclaimed and allocation succeeds, |
22 |
eventually. In the worst case, the oom killer is invoked, which is |
23 |
proper outcome if user sets up zram too large (in comparison to |
24 |
available RAM). |
25 |
|
26 |
Link: https://bugzilla.suse.com/show_bug.cgi?id=1202203 |
27 |
Fixes: e7be8d1dd983 ("zram: remove double compression logic") |
28 |
Cc: stable@vger.kernel.org # 5.19 |
29 |
Cc: Minchan Kim <minchan@kernel.org> |
30 |
Cc: Nitin Gupta <ngupta@vflare.org> |
31 |
Cc: Sergey Senozhatsky <senozhatsky@chromium.org> |
32 |
Cc: Alexey Romanov <avromanov@sberdevices.ru> |
33 |
Cc: Dmitry Rokosov <ddrokosov@sberdevices.ru> |
34 |
Cc: Lukas Czerner <lczerner@redhat.com> |
35 |
Cc: Ext4 Developers List <linux-ext4@vger.kernel.org> |
36 |
Signed-off-by: Jiri Slaby <jslaby@suse.cz> |
37 |
|
38 |
--- |
39 |
drivers/block/zram/zram_drv.c | 42 ++++++++++++++++++++++++++--------- |
40 |
drivers/block/zram/zram_drv.h | 1 + |
41 |
2 files changed, 33 insertions(+), 10 deletions(-) |
42 |
|
43 |
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c |
44 |
index b8549c61ff2c..b144be41290e 100644 |
45 |
--- a/drivers/block/zram/zram_drv.c |
46 |
+++ b/drivers/block/zram/zram_drv.c |
47 |
@@ -1144,14 +1144,15 @@ static ssize_t bd_stat_show(struct device *dev, |
48 |
static ssize_t debug_stat_show(struct device *dev, |
49 |
struct device_attribute *attr, char *buf) |
50 |
{ |
51 |
- int version = 2; |
52 |
+ int version = 1; |
53 |
struct zram *zram = dev_to_zram(dev); |
54 |
ssize_t ret; |
55 |
|
56 |
down_read(&zram->init_lock); |
57 |
ret = scnprintf(buf, PAGE_SIZE, |
58 |
- "version: %d\n%8llu\n", |
59 |
+ "version: %d\n%8llu %8llu\n", |
60 |
version, |
61 |
+ (u64)atomic64_read(&zram->stats.writestall), |
62 |
(u64)atomic64_read(&zram->stats.miss_free)); |
63 |
up_read(&zram->init_lock); |
64 |
|
65 |
@@ -1367,6 +1368,7 @@ static int __zram_bvec_write(struct zram *zram, struct bio_vec *bvec, |
66 |
} |
67 |
kunmap_atomic(mem); |
68 |
|
69 |
+compress_again: |
70 |
zstrm = zcomp_stream_get(zram->comp); |
71 |
src = kmap_atomic(page); |
72 |
ret = zcomp_compress(zstrm, src, &comp_len); |
73 |
@@ -1375,20 +1377,39 @@ static int __zram_bvec_write(struct zram *zram, struct bio_vec *bvec, |
74 |
if (unlikely(ret)) { |
75 |
zcomp_stream_put(zram->comp); |
76 |
pr_err("Compression failed! err=%d\n", ret); |
77 |
+ zs_free(zram->mem_pool, handle); |
78 |
return ret; |
79 |
} |
80 |
|
81 |
if (comp_len >= huge_class_size) |
82 |
comp_len = PAGE_SIZE; |
83 |
- |
84 |
- handle = zs_malloc(zram->mem_pool, comp_len, |
85 |
- __GFP_KSWAPD_RECLAIM | |
86 |
- __GFP_NOWARN | |
87 |
- __GFP_HIGHMEM | |
88 |
- __GFP_MOVABLE); |
89 |
- |
90 |
- if (unlikely(!handle)) { |
91 |
+ /* |
92 |
+ * handle allocation has 2 paths: |
93 |
+ * a) fast path is executed with preemption disabled (for |
94 |
+ * per-cpu streams) and has __GFP_DIRECT_RECLAIM bit clear, |
95 |
+ * since we can't sleep; |
96 |
+ * b) slow path enables preemption and attempts to allocate |
97 |
+ * the page with __GFP_DIRECT_RECLAIM bit set. we have to |
98 |
+ * put per-cpu compression stream and, thus, to re-do |
99 |
+ * the compression once handle is allocated. |
100 |
+ * |
101 |
+ * if we have a 'non-null' handle here then we are coming |
102 |
+ * from the slow path and handle has already been allocated. |
103 |
+ */ |
104 |
+ if (!handle) |
105 |
+ handle = zs_malloc(zram->mem_pool, comp_len, |
106 |
+ __GFP_KSWAPD_RECLAIM | |
107 |
+ __GFP_NOWARN | |
108 |
+ __GFP_HIGHMEM | |
109 |
+ __GFP_MOVABLE); |
110 |
+ if (!handle) { |
111 |
zcomp_stream_put(zram->comp); |
112 |
+ atomic64_inc(&zram->stats.writestall); |
113 |
+ handle = zs_malloc(zram->mem_pool, comp_len, |
114 |
+ GFP_NOIO | __GFP_HIGHMEM | |
115 |
+ __GFP_MOVABLE); |
116 |
+ if (handle) |
117 |
+ goto compress_again; |
118 |
return -ENOMEM; |
119 |
} |
120 |
|
121 |
@@ -1946,6 +1967,7 @@ static int zram_add(void) |
122 |
if (ZRAM_LOGICAL_BLOCK_SIZE == PAGE_SIZE) |
123 |
blk_queue_max_write_zeroes_sectors(zram->disk->queue, UINT_MAX); |
124 |
|
125 |
+ blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, zram->disk->queue); |
126 |
ret = device_add_disk(NULL, zram->disk, zram_disk_groups); |
127 |
if (ret) |
128 |
goto out_cleanup_disk; |
129 |
diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h |
130 |
index 158c91e54850..80c3b43b4828 100644 |
131 |
--- a/drivers/block/zram/zram_drv.h |
132 |
+++ b/drivers/block/zram/zram_drv.h |
133 |
@@ -81,6 +81,7 @@ struct zram_stats { |
134 |
atomic64_t huge_pages_since; /* no. of huge pages since zram set up */ |
135 |
atomic64_t pages_stored; /* no. of pages currently stored */ |
136 |
atomic_long_t max_used_pages; /* no. of maximum pages stored */ |
137 |
+ atomic64_t writestall; /* no. of write slow paths */ |
138 |
atomic64_t miss_free; /* no. of missed free */ |
139 |
#ifdef CONFIG_ZRAM_WRITEBACK |
140 |
atomic64_t bd_count; /* no. of pages in backing device */ |
141 |
-- |
142 |
2.37.1 |
143 |
|