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 } 182