File Index
Files and directories
Sign in
FILE

decompressor_crypto.c

File preview with syntax highlighting.

linux-6.19.14/fs/erofs/decompressor_crypto.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2#include <linux/scatterlist.h>
  3#include <crypto/acompress.h>
  4#include "compress.h"
  5
  6static 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);
 53failed_dst_alloc:
 54	sg_free_table(&st_src);
 55failed_src_alloc:
 56	acomp_request_free(req);
 57	return ret;
 58}
 59
 60struct z_erofs_crypto_engine {
 61	char *crypto_name;
 62	struct crypto_acomp *tfm;
 63};
 64
 65struct 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};
 80static DECLARE_RWSEM(z_erofs_crypto_rwsem);
 81
 82static 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
 92int 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);
120out:
121	up_read(&z_erofs_crypto_rwsem);
122	return err;
123}
124
125int 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
151void 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
168int 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}
~/ Read-only file preview.