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