Skip to content

Commit b4a29ef

Browse files
Bo Liuhsiangkao
authored andcommitted
erofs: support DEFLATE decompression by using Intel QAT
This patch introduces the use of the Intel QAT to offload EROFS data decompression, aiming to improve the decompression performance. A 285MiB dataset is used with the following command to create EROFS images with different cluster sizes: $ mkfs.erofs -zdeflate,level=9 -C{4096,16384,65536,131072,262144} Fio is used to test the following read patterns: $ fio -filename=testfile -bs=4k -rw=read -name=job1 $ fio -filename=testfile -bs=4k -rw=randread -name=job1 $ fio -filename=testfile -bs=4k -rw=randread --io_size=14m -name=job1 Here are some performance numbers for reference: Processors: Intel(R) Xeon(R) 6766E (144 cores) Memory: 512 GiB |-----------------------------------------------------------------------------| | | Cluster size | sequential read | randread | small randread(5%) | |-----------|--------------|-----------------|-----------|--------------------| | Intel QAT | 4096 | 538 MiB/s | 112 MiB/s | 20.76 MiB/s | | Intel QAT | 16384 | 699 MiB/s | 158 MiB/s | 21.02 MiB/s | | Intel QAT | 65536 | 917 MiB/s | 278 MiB/s | 20.90 MiB/s | | Intel QAT | 131072 | 1056 MiB/s | 351 MiB/s | 23.36 MiB/s | | Intel QAT | 262144 | 1145 MiB/s | 431 MiB/s | 26.66 MiB/s | | deflate | 4096 | 499 MiB/s | 108 MiB/s | 21.50 MiB/s | | deflate | 16384 | 422 MiB/s | 125 MiB/s | 18.94 MiB/s | | deflate | 65536 | 452 MiB/s | 159 MiB/s | 13.02 MiB/s | | deflate | 131072 | 452 MiB/s | 177 MiB/s | 11.44 MiB/s | | deflate | 262144 | 466 MiB/s | 194 MiB/s | 10.60 MiB/s | Signed-off-by: Bo Liu <[email protected]> Reviewed-by: Gao Xiang <[email protected]> Link: https://lore.kernel.org/r/[email protected] [ Gao Xiang: refine the commit message. ] Signed-off-by: Gao Xiang <[email protected]>
1 parent 17a2a72 commit b4a29ef

File tree

8 files changed

+265
-5
lines changed

8 files changed

+265
-5
lines changed

Documentation/ABI/testing/sysfs-fs-erofs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,11 @@ Description: Writing to this will drop compression-related caches,
2727
- 1 : invalidate cached compressed folios
2828
- 2 : drop in-memory pclusters
2929
- 3 : drop in-memory pclusters and cached compressed folios
30+
31+
What: /sys/fs/erofs/accel
32+
Date: May 2025
33+
Contact: "Bo Liu" <[email protected]>
34+
Description: Used to set or show hardware accelerators in effect
35+
and multiple accelerators are separated by '\n'.
36+
Supported accelerator(s): qat_deflate.
37+
Disable all accelerators with an empty string (echo > accel).

fs/erofs/Kconfig

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,20 @@ config EROFS_FS_ZIP_ZSTD
144144

145145
If unsure, say N.
146146

147+
config EROFS_FS_ZIP_ACCEL
148+
bool "EROFS hardware decompression support"
149+
depends on EROFS_FS_ZIP
150+
help
151+
Saying Y here includes hardware accelerator support for reading
152+
EROFS file systems containing compressed data. It gives better
153+
decompression speed than the software-implemented decompression, and
154+
it costs lower CPU overhead.
155+
156+
Hardware accelerator support is an experimental feature for now and
157+
file systems are still readable without selecting this option.
158+
159+
If unsure, say N.
160+
147161
config EROFS_FS_ONDEMAND
148162
bool "EROFS fscache-based on-demand read support (deprecated)"
149163
depends on EROFS_FS

fs/erofs/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ erofs-$(CONFIG_EROFS_FS_ZIP) += decompressor.o zmap.o zdata.o zutil.o
77
erofs-$(CONFIG_EROFS_FS_ZIP_LZMA) += decompressor_lzma.o
88
erofs-$(CONFIG_EROFS_FS_ZIP_DEFLATE) += decompressor_deflate.o
99
erofs-$(CONFIG_EROFS_FS_ZIP_ZSTD) += decompressor_zstd.o
10+
erofs-$(CONFIG_EROFS_FS_ZIP_ACCEL) += decompressor_crypto.o
1011
erofs-$(CONFIG_EROFS_FS_BACKED_BY_FILE) += fileio.o
1112
erofs-$(CONFIG_EROFS_FS_ONDEMAND) += fscache.o

fs/erofs/compress.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,14 @@ int z_erofs_fixup_insize(struct z_erofs_decompress_req *rq, const char *padbuf,
7676
unsigned int padbufsize);
7777
int __init z_erofs_init_decompressor(void);
7878
void z_erofs_exit_decompressor(void);
79+
int z_erofs_crypto_decompress(struct z_erofs_decompress_req *rq,
80+
struct page **pgpl);
81+
int z_erofs_crypto_enable_engine(const char *name, int len);
82+
#ifdef CONFIG_EROFS_FS_ZIP_ACCEL
83+
void z_erofs_crypto_disable_all_engines(void);
84+
int z_erofs_crypto_show_engines(char *buf, int size, char sep);
85+
#else
86+
static inline void z_erofs_crypto_disable_all_engines(void) {}
87+
static inline int z_erofs_crypto_show_engines(char *buf, int size, char sep) { return 0; }
88+
#endif
7989
#endif

fs/erofs/decompressor_crypto.c

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
#include <linux/scatterlist.h>
3+
#include <crypto/acompress.h>
4+
#include "compress.h"
5+
6+
static int __z_erofs_crypto_decompress(struct z_erofs_decompress_req *rq,
7+
struct crypto_acomp *tfm)
8+
{
9+
struct sg_table st_src, st_dst;
10+
struct acomp_req *req;
11+
struct crypto_wait wait;
12+
u8 *headpage;
13+
int ret;
14+
15+
headpage = kmap_local_page(*rq->in);
16+
ret = z_erofs_fixup_insize(rq, headpage + rq->pageofs_in,
17+
min_t(unsigned int, rq->inputsize,
18+
rq->sb->s_blocksize - rq->pageofs_in));
19+
kunmap_local(headpage);
20+
if (ret)
21+
return ret;
22+
23+
req = acomp_request_alloc(tfm);
24+
if (!req)
25+
return -ENOMEM;
26+
27+
ret = sg_alloc_table_from_pages_segment(&st_src, rq->in, rq->inpages,
28+
rq->pageofs_in, rq->inputsize, UINT_MAX, GFP_KERNEL);
29+
if (ret < 0)
30+
goto failed_src_alloc;
31+
32+
ret = sg_alloc_table_from_pages_segment(&st_dst, rq->out, rq->outpages,
33+
rq->pageofs_out, rq->outputsize, UINT_MAX, GFP_KERNEL);
34+
if (ret < 0)
35+
goto failed_dst_alloc;
36+
37+
acomp_request_set_params(req, st_src.sgl,
38+
st_dst.sgl, rq->inputsize, rq->outputsize);
39+
40+
crypto_init_wait(&wait);
41+
acomp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
42+
crypto_req_done, &wait);
43+
44+
ret = crypto_wait_req(crypto_acomp_decompress(req), &wait);
45+
if (ret) {
46+
erofs_err(rq->sb, "failed to decompress %d in[%u, %u] out[%u]",
47+
ret, rq->inputsize, rq->pageofs_in, rq->outputsize);
48+
ret = -EIO;
49+
}
50+
51+
sg_free_table(&st_dst);
52+
failed_dst_alloc:
53+
sg_free_table(&st_src);
54+
failed_src_alloc:
55+
acomp_request_free(req);
56+
return ret;
57+
}
58+
59+
struct z_erofs_crypto_engine {
60+
char *crypto_name;
61+
struct crypto_acomp *tfm;
62+
};
63+
64+
struct z_erofs_crypto_engine *z_erofs_crypto[Z_EROFS_COMPRESSION_MAX] = {
65+
[Z_EROFS_COMPRESSION_LZ4] = (struct z_erofs_crypto_engine[]) {
66+
{},
67+
},
68+
[Z_EROFS_COMPRESSION_LZMA] = (struct z_erofs_crypto_engine[]) {
69+
{},
70+
},
71+
[Z_EROFS_COMPRESSION_DEFLATE] = (struct z_erofs_crypto_engine[]) {
72+
{ .crypto_name = "qat_deflate", },
73+
{},
74+
},
75+
[Z_EROFS_COMPRESSION_ZSTD] = (struct z_erofs_crypto_engine[]) {
76+
{},
77+
},
78+
};
79+
static DECLARE_RWSEM(z_erofs_crypto_rwsem);
80+
81+
static struct crypto_acomp *z_erofs_crypto_get_engine(int alg)
82+
{
83+
struct z_erofs_crypto_engine *e;
84+
85+
for (e = z_erofs_crypto[alg]; e->crypto_name; ++e)
86+
if (e->tfm)
87+
return e->tfm;
88+
return NULL;
89+
}
90+
91+
int z_erofs_crypto_decompress(struct z_erofs_decompress_req *rq,
92+
struct page **pgpl)
93+
{
94+
struct crypto_acomp *tfm;
95+
int i, err;
96+
97+
down_read(&z_erofs_crypto_rwsem);
98+
tfm = z_erofs_crypto_get_engine(rq->alg);
99+
if (!tfm) {
100+
err = -EOPNOTSUPP;
101+
goto out;
102+
}
103+
104+
for (i = 0; i < rq->outpages; i++) {
105+
struct page *const page = rq->out[i];
106+
struct page *victim;
107+
108+
if (!page) {
109+
victim = __erofs_allocpage(pgpl, rq->gfp, true);
110+
if (!victim) {
111+
err = -ENOMEM;
112+
goto out;
113+
}
114+
set_page_private(victim, Z_EROFS_SHORTLIVED_PAGE);
115+
rq->out[i] = victim;
116+
}
117+
}
118+
err = __z_erofs_crypto_decompress(rq, tfm);
119+
out:
120+
up_read(&z_erofs_crypto_rwsem);
121+
return err;
122+
}
123+
124+
int z_erofs_crypto_enable_engine(const char *name, int len)
125+
{
126+
struct z_erofs_crypto_engine *e;
127+
struct crypto_acomp *tfm;
128+
int alg;
129+
130+
down_write(&z_erofs_crypto_rwsem);
131+
for (alg = 0; alg < Z_EROFS_COMPRESSION_MAX; ++alg) {
132+
for (e = z_erofs_crypto[alg]; e->crypto_name; ++e) {
133+
if (!strncmp(name, e->crypto_name, len)) {
134+
if (e->tfm)
135+
break;
136+
tfm = crypto_alloc_acomp(e->crypto_name, 0, 0);
137+
if (IS_ERR(tfm)) {
138+
up_write(&z_erofs_crypto_rwsem);
139+
return -EOPNOTSUPP;
140+
}
141+
e->tfm = tfm;
142+
break;
143+
}
144+
}
145+
}
146+
up_write(&z_erofs_crypto_rwsem);
147+
return 0;
148+
}
149+
150+
void z_erofs_crypto_disable_all_engines(void)
151+
{
152+
struct z_erofs_crypto_engine *e;
153+
int alg;
154+
155+
down_write(&z_erofs_crypto_rwsem);
156+
for (alg = 0; alg < Z_EROFS_COMPRESSION_MAX; ++alg) {
157+
for (e = z_erofs_crypto[alg]; e->crypto_name; ++e) {
158+
if (!e->tfm)
159+
continue;
160+
crypto_free_acomp(e->tfm);
161+
e->tfm = NULL;
162+
}
163+
}
164+
up_write(&z_erofs_crypto_rwsem);
165+
}
166+
167+
int z_erofs_crypto_show_engines(char *buf, int size, char sep)
168+
{
169+
struct z_erofs_crypto_engine *e;
170+
int alg, len = 0;
171+
172+
for (alg = 0; alg < Z_EROFS_COMPRESSION_MAX; ++alg) {
173+
for (e = z_erofs_crypto[alg]; e->crypto_name; ++e) {
174+
if (!e->tfm)
175+
continue;
176+
len += scnprintf(buf + len, size - len, "%s%c",
177+
e->crypto_name, sep);
178+
}
179+
}
180+
return len;
181+
}

fs/erofs/decompressor_deflate.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,8 @@ static int z_erofs_load_deflate_config(struct super_block *sb,
9797
return -ENOMEM;
9898
}
9999

100-
static int z_erofs_deflate_decompress(struct z_erofs_decompress_req *rq,
101-
struct page **pgpl)
100+
static int __z_erofs_deflate_decompress(struct z_erofs_decompress_req *rq,
101+
struct page **pgpl)
102102
{
103103
struct super_block *sb = rq->sb;
104104
struct z_erofs_stream_dctx dctx = { .rq = rq, .no = -1, .ni = 0 };
@@ -178,6 +178,22 @@ static int z_erofs_deflate_decompress(struct z_erofs_decompress_req *rq,
178178
return err;
179179
}
180180

181+
static int z_erofs_deflate_decompress(struct z_erofs_decompress_req *rq,
182+
struct page **pgpl)
183+
{
184+
#ifdef CONFIG_EROFS_FS_ZIP_ACCEL
185+
int err;
186+
187+
if (!rq->partial_decoding) {
188+
err = z_erofs_crypto_decompress(rq, pgpl);
189+
if (err != -EOPNOTSUPP)
190+
return err;
191+
192+
}
193+
#endif
194+
return __z_erofs_deflate_decompress(rq, pgpl);
195+
}
196+
181197
const struct z_erofs_decompressor z_erofs_deflate_decomp = {
182198
.config = z_erofs_load_deflate_config,
183199
.decompress = z_erofs_deflate_decompress,

fs/erofs/sysfs.c

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@
77
#include <linux/kobject.h>
88

99
#include "internal.h"
10+
#include "compress.h"
1011

1112
enum {
1213
attr_feature,
1314
attr_drop_caches,
1415
attr_pointer_ui,
1516
attr_pointer_bool,
17+
attr_accel,
1618
};
1719

1820
enum {
@@ -60,14 +62,25 @@ static struct erofs_attr erofs_attr_##_name = { \
6062
EROFS_ATTR_RW_UI(sync_decompress, erofs_mount_opts);
6163
EROFS_ATTR_FUNC(drop_caches, 0200);
6264
#endif
65+
#ifdef CONFIG_EROFS_FS_ZIP_ACCEL
66+
EROFS_ATTR_FUNC(accel, 0644);
67+
#endif
6368

64-
static struct attribute *erofs_attrs[] = {
69+
static struct attribute *erofs_sb_attrs[] = {
6570
#ifdef CONFIG_EROFS_FS_ZIP
6671
ATTR_LIST(sync_decompress),
6772
ATTR_LIST(drop_caches),
6873
#endif
6974
NULL,
7075
};
76+
ATTRIBUTE_GROUPS(erofs_sb);
77+
78+
static struct attribute *erofs_attrs[] = {
79+
#ifdef CONFIG_EROFS_FS_ZIP_ACCEL
80+
ATTR_LIST(accel),
81+
#endif
82+
NULL,
83+
};
7184
ATTRIBUTE_GROUPS(erofs);
7285

7386
/* Features this copy of erofs supports */
@@ -128,12 +141,14 @@ static ssize_t erofs_attr_show(struct kobject *kobj,
128141
if (!ptr)
129142
return 0;
130143
return sysfs_emit(buf, "%d\n", *(bool *)ptr);
144+
case attr_accel:
145+
return z_erofs_crypto_show_engines(buf, PAGE_SIZE, '\n');
131146
}
132147
return 0;
133148
}
134149

135150
static ssize_t erofs_attr_store(struct kobject *kobj, struct attribute *attr,
136-
const char *buf, size_t len)
151+
const char *buf, size_t len)
137152
{
138153
struct erofs_sb_info *sbi = container_of(kobj, struct erofs_sb_info,
139154
s_kobj);
@@ -181,6 +196,19 @@ static ssize_t erofs_attr_store(struct kobject *kobj, struct attribute *attr,
181196
if (t & 1)
182197
invalidate_mapping_pages(MNGD_MAPPING(sbi), 0, -1);
183198
return len;
199+
#endif
200+
#ifdef CONFIG_EROFS_FS_ZIP_ACCEL
201+
case attr_accel:
202+
buf = skip_spaces(buf);
203+
z_erofs_crypto_disable_all_engines();
204+
while (*buf) {
205+
t = strcspn(buf, "\n");
206+
ret = z_erofs_crypto_enable_engine(buf, t);
207+
if (ret < 0)
208+
return ret;
209+
buf += buf[t] != '\0' ? t + 1 : t;
210+
}
211+
return len;
184212
#endif
185213
}
186214
return 0;
@@ -199,12 +227,13 @@ static const struct sysfs_ops erofs_attr_ops = {
199227
};
200228

201229
static const struct kobj_type erofs_sb_ktype = {
202-
.default_groups = erofs_groups,
230+
.default_groups = erofs_sb_groups,
203231
.sysfs_ops = &erofs_attr_ops,
204232
.release = erofs_sb_release,
205233
};
206234

207235
static const struct kobj_type erofs_ktype = {
236+
.default_groups = erofs_groups,
208237
.sysfs_ops = &erofs_attr_ops,
209238
};
210239

fs/erofs/zdata.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,7 @@ void z_erofs_exit_subsystem(void)
441441
z_erofs_destroy_pcpu_workers();
442442
destroy_workqueue(z_erofs_workqueue);
443443
z_erofs_destroy_pcluster_pool();
444+
z_erofs_crypto_disable_all_engines();
444445
z_erofs_exit_decompressor();
445446
}
446447

0 commit comments

Comments
 (0)