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