| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182 |
- // SPDX-License-Identifier: GPL-2.0-or-later
- #include <linux/scatterlist.h>
- #include <crypto/acompress.h>
- #include "compress.h"
- static int __z_erofs_crypto_decompress(struct z_erofs_decompress_req *rq,
- struct crypto_acomp *tfm)
- {
- struct sg_table st_src, st_dst;
- struct acomp_req *req;
- struct crypto_wait wait;
- const char *reason;
- u8 *headpage;
- int ret;
- headpage = kmap_local_page(*rq->in);
- reason = z_erofs_fixup_insize(rq, headpage + rq->pageofs_in,
- min_t(unsigned int, rq->inputsize,
- rq->sb->s_blocksize - rq->pageofs_in));
- kunmap_local(headpage);
- if (reason)
- return IS_ERR(reason) ? PTR_ERR(reason) : -EFSCORRUPTED;
- req = acomp_request_alloc(tfm);
- if (!req)
- return -ENOMEM;
- ret = sg_alloc_table_from_pages_segment(&st_src, rq->in, rq->inpages,
- rq->pageofs_in, rq->inputsize, UINT_MAX, GFP_KERNEL);
- if (ret < 0)
- goto failed_src_alloc;
- ret = sg_alloc_table_from_pages_segment(&st_dst, rq->out, rq->outpages,
- rq->pageofs_out, rq->outputsize, UINT_MAX, GFP_KERNEL);
- if (ret < 0)
- goto failed_dst_alloc;
- acomp_request_set_params(req, st_src.sgl,
- st_dst.sgl, rq->inputsize, rq->outputsize);
- crypto_init_wait(&wait);
- acomp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
- crypto_req_done, &wait);
- ret = crypto_wait_req(crypto_acomp_decompress(req), &wait);
- if (ret) {
- erofs_err(rq->sb, "failed to decompress %d in[%u, %u] out[%u]",
- ret, rq->inputsize, rq->pageofs_in, rq->outputsize);
- ret = -EIO;
- }
- sg_free_table(&st_dst);
- failed_dst_alloc:
- sg_free_table(&st_src);
- failed_src_alloc:
- acomp_request_free(req);
- return ret;
- }
- struct z_erofs_crypto_engine {
- char *crypto_name;
- struct crypto_acomp *tfm;
- };
- static struct z_erofs_crypto_engine *z_erofs_crypto[Z_EROFS_COMPRESSION_MAX] = {
- [Z_EROFS_COMPRESSION_LZ4] = (struct z_erofs_crypto_engine[]) {
- {},
- },
- [Z_EROFS_COMPRESSION_LZMA] = (struct z_erofs_crypto_engine[]) {
- {},
- },
- [Z_EROFS_COMPRESSION_DEFLATE] = (struct z_erofs_crypto_engine[]) {
- { .crypto_name = "qat_deflate", },
- {},
- },
- [Z_EROFS_COMPRESSION_ZSTD] = (struct z_erofs_crypto_engine[]) {
- {},
- },
- };
- static DECLARE_RWSEM(z_erofs_crypto_rwsem);
- static struct crypto_acomp *z_erofs_crypto_get_engine(int alg)
- {
- struct z_erofs_crypto_engine *e;
- for (e = z_erofs_crypto[alg]; e->crypto_name; ++e)
- if (e->tfm)
- return e->tfm;
- return NULL;
- }
- int z_erofs_crypto_decompress(struct z_erofs_decompress_req *rq,
- struct page **pgpl)
- {
- struct crypto_acomp *tfm;
- int i, err;
- down_read(&z_erofs_crypto_rwsem);
- tfm = z_erofs_crypto_get_engine(rq->alg);
- if (!tfm) {
- err = -EOPNOTSUPP;
- goto out;
- }
- for (i = 0; i < rq->outpages; i++) {
- struct page *const page = rq->out[i];
- struct page *victim;
- if (!page) {
- victim = __erofs_allocpage(pgpl, rq->gfp, true);
- if (!victim) {
- err = -ENOMEM;
- goto out;
- }
- set_page_private(victim, Z_EROFS_SHORTLIVED_PAGE);
- rq->out[i] = victim;
- }
- }
- err = __z_erofs_crypto_decompress(rq, tfm);
- out:
- up_read(&z_erofs_crypto_rwsem);
- return err;
- }
- int z_erofs_crypto_enable_engine(const char *name, int len)
- {
- struct z_erofs_crypto_engine *e;
- struct crypto_acomp *tfm;
- int alg;
- down_write(&z_erofs_crypto_rwsem);
- for (alg = 0; alg < Z_EROFS_COMPRESSION_MAX; ++alg) {
- for (e = z_erofs_crypto[alg]; e->crypto_name; ++e) {
- if (!strncmp(name, e->crypto_name, len)) {
- if (e->tfm)
- break;
- tfm = crypto_alloc_acomp(e->crypto_name, 0, 0);
- if (IS_ERR(tfm)) {
- up_write(&z_erofs_crypto_rwsem);
- return -EOPNOTSUPP;
- }
- e->tfm = tfm;
- break;
- }
- }
- }
- up_write(&z_erofs_crypto_rwsem);
- return 0;
- }
- void z_erofs_crypto_disable_all_engines(void)
- {
- struct z_erofs_crypto_engine *e;
- int alg;
- down_write(&z_erofs_crypto_rwsem);
- for (alg = 0; alg < Z_EROFS_COMPRESSION_MAX; ++alg) {
- for (e = z_erofs_crypto[alg]; e->crypto_name; ++e) {
- if (!e->tfm)
- continue;
- crypto_free_acomp(e->tfm);
- e->tfm = NULL;
- }
- }
- up_write(&z_erofs_crypto_rwsem);
- }
- int z_erofs_crypto_show_engines(char *buf, int size, char sep)
- {
- struct z_erofs_crypto_engine *e;
- int alg, len = 0;
- for (alg = 0; alg < Z_EROFS_COMPRESSION_MAX; ++alg) {
- for (e = z_erofs_crypto[alg]; e->crypto_name; ++e) {
- if (!e->tfm)
- continue;
- len += scnprintf(buf + len, size - len, "%s%c",
- e->crypto_name, sep);
- }
- }
- return len;
- }
|