xref: /linux/fs/erofs/decompressor_crypto.c (revision 6dfafbd0299a60bfb5d5e277fdf100037c7ded07)
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