acompress.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Asynchronous Compression operations
  4. *
  5. * Copyright (c) 2016, Intel Corporation
  6. * Authors: Weigang Li <weigang.li@intel.com>
  7. * Giovanni Cabiddu <giovanni.cabiddu@intel.com>
  8. */
  9. #include <crypto/internal/acompress.h>
  10. #include <crypto/scatterwalk.h>
  11. #include <linux/cryptouser.h>
  12. #include <linux/cpumask.h>
  13. #include <linux/err.h>
  14. #include <linux/kernel.h>
  15. #include <linux/module.h>
  16. #include <linux/percpu.h>
  17. #include <linux/scatterlist.h>
  18. #include <linux/sched.h>
  19. #include <linux/seq_file.h>
  20. #include <linux/smp.h>
  21. #include <linux/spinlock.h>
  22. #include <linux/string.h>
  23. #include <linux/workqueue.h>
  24. #include <net/netlink.h>
  25. #include "compress.h"
  26. struct crypto_scomp;
  27. enum {
  28. ACOMP_WALK_SLEEP = 1 << 0,
  29. ACOMP_WALK_SRC_LINEAR = 1 << 1,
  30. ACOMP_WALK_DST_LINEAR = 1 << 2,
  31. };
  32. static const struct crypto_type crypto_acomp_type;
  33. static void acomp_reqchain_done(void *data, int err);
  34. static inline struct acomp_alg *__crypto_acomp_alg(struct crypto_alg *alg)
  35. {
  36. return container_of(alg, struct acomp_alg, calg.base);
  37. }
  38. static inline struct acomp_alg *crypto_acomp_alg(struct crypto_acomp *tfm)
  39. {
  40. return __crypto_acomp_alg(crypto_acomp_tfm(tfm)->__crt_alg);
  41. }
  42. static int __maybe_unused crypto_acomp_report(
  43. struct sk_buff *skb, struct crypto_alg *alg)
  44. {
  45. struct crypto_report_acomp racomp;
  46. memset(&racomp, 0, sizeof(racomp));
  47. strscpy(racomp.type, "acomp", sizeof(racomp.type));
  48. return nla_put(skb, CRYPTOCFGA_REPORT_ACOMP, sizeof(racomp), &racomp);
  49. }
  50. static void __maybe_unused crypto_acomp_show(struct seq_file *m,
  51. struct crypto_alg *alg)
  52. {
  53. seq_puts(m, "type : acomp\n");
  54. }
  55. static void crypto_acomp_exit_tfm(struct crypto_tfm *tfm)
  56. {
  57. struct crypto_acomp *acomp = __crypto_acomp_tfm(tfm);
  58. struct acomp_alg *alg = crypto_acomp_alg(acomp);
  59. if (alg->exit)
  60. alg->exit(acomp);
  61. if (acomp_is_async(acomp))
  62. crypto_free_acomp(crypto_acomp_fb(acomp));
  63. }
  64. static int crypto_acomp_init_tfm(struct crypto_tfm *tfm)
  65. {
  66. struct crypto_acomp *acomp = __crypto_acomp_tfm(tfm);
  67. struct acomp_alg *alg = crypto_acomp_alg(acomp);
  68. struct crypto_acomp *fb = NULL;
  69. int err;
  70. if (tfm->__crt_alg->cra_type != &crypto_acomp_type)
  71. return crypto_init_scomp_ops_async(tfm);
  72. if (acomp_is_async(acomp)) {
  73. fb = crypto_alloc_acomp(crypto_acomp_alg_name(acomp), 0,
  74. CRYPTO_ALG_ASYNC);
  75. if (IS_ERR(fb))
  76. return PTR_ERR(fb);
  77. err = -EINVAL;
  78. if (crypto_acomp_reqsize(fb) > MAX_SYNC_COMP_REQSIZE)
  79. goto out_free_fb;
  80. tfm->fb = crypto_acomp_tfm(fb);
  81. }
  82. acomp->compress = alg->compress;
  83. acomp->decompress = alg->decompress;
  84. acomp->reqsize = alg->base.cra_reqsize;
  85. acomp->base.exit = crypto_acomp_exit_tfm;
  86. if (!alg->init)
  87. return 0;
  88. err = alg->init(acomp);
  89. if (err)
  90. goto out_free_fb;
  91. return 0;
  92. out_free_fb:
  93. crypto_free_acomp(fb);
  94. return err;
  95. }
  96. static unsigned int crypto_acomp_extsize(struct crypto_alg *alg)
  97. {
  98. int extsize = crypto_alg_extsize(alg);
  99. if (alg->cra_type != &crypto_acomp_type)
  100. extsize += sizeof(struct crypto_scomp *);
  101. return extsize;
  102. }
  103. static const struct crypto_type crypto_acomp_type = {
  104. .extsize = crypto_acomp_extsize,
  105. .init_tfm = crypto_acomp_init_tfm,
  106. #ifdef CONFIG_PROC_FS
  107. .show = crypto_acomp_show,
  108. #endif
  109. #if IS_ENABLED(CONFIG_CRYPTO_USER)
  110. .report = crypto_acomp_report,
  111. #endif
  112. .maskclear = ~CRYPTO_ALG_TYPE_MASK,
  113. .maskset = CRYPTO_ALG_TYPE_ACOMPRESS_MASK,
  114. .type = CRYPTO_ALG_TYPE_ACOMPRESS,
  115. .tfmsize = offsetof(struct crypto_acomp, base),
  116. .algsize = offsetof(struct acomp_alg, base),
  117. };
  118. struct crypto_acomp *crypto_alloc_acomp(const char *alg_name, u32 type,
  119. u32 mask)
  120. {
  121. return crypto_alloc_tfm(alg_name, &crypto_acomp_type, type, mask);
  122. }
  123. EXPORT_SYMBOL_GPL(crypto_alloc_acomp);
  124. struct crypto_acomp *crypto_alloc_acomp_node(const char *alg_name, u32 type,
  125. u32 mask, int node)
  126. {
  127. return crypto_alloc_tfm_node(alg_name, &crypto_acomp_type, type, mask,
  128. node);
  129. }
  130. EXPORT_SYMBOL_GPL(crypto_alloc_acomp_node);
  131. static void acomp_save_req(struct acomp_req *req, crypto_completion_t cplt)
  132. {
  133. struct acomp_req_chain *state = &req->chain;
  134. state->compl = req->base.complete;
  135. state->data = req->base.data;
  136. req->base.complete = cplt;
  137. req->base.data = state;
  138. }
  139. static void acomp_restore_req(struct acomp_req *req)
  140. {
  141. struct acomp_req_chain *state = req->base.data;
  142. req->base.complete = state->compl;
  143. req->base.data = state->data;
  144. }
  145. static void acomp_reqchain_virt(struct acomp_req *req)
  146. {
  147. struct acomp_req_chain *state = &req->chain;
  148. unsigned int slen = req->slen;
  149. unsigned int dlen = req->dlen;
  150. if (state->flags & CRYPTO_ACOMP_REQ_SRC_VIRT)
  151. acomp_request_set_src_dma(req, state->src, slen);
  152. if (state->flags & CRYPTO_ACOMP_REQ_DST_VIRT)
  153. acomp_request_set_dst_dma(req, state->dst, dlen);
  154. }
  155. static void acomp_virt_to_sg(struct acomp_req *req)
  156. {
  157. struct acomp_req_chain *state = &req->chain;
  158. state->flags = req->base.flags & (CRYPTO_ACOMP_REQ_SRC_VIRT |
  159. CRYPTO_ACOMP_REQ_DST_VIRT);
  160. if (acomp_request_src_isvirt(req)) {
  161. unsigned int slen = req->slen;
  162. const u8 *svirt = req->svirt;
  163. state->src = svirt;
  164. sg_init_one(&state->ssg, svirt, slen);
  165. acomp_request_set_src_sg(req, &state->ssg, slen);
  166. }
  167. if (acomp_request_dst_isvirt(req)) {
  168. unsigned int dlen = req->dlen;
  169. u8 *dvirt = req->dvirt;
  170. state->dst = dvirt;
  171. sg_init_one(&state->dsg, dvirt, dlen);
  172. acomp_request_set_dst_sg(req, &state->dsg, dlen);
  173. }
  174. }
  175. static int acomp_do_nondma(struct acomp_req *req, bool comp)
  176. {
  177. ACOMP_FBREQ_ON_STACK(fbreq, req);
  178. int err;
  179. if (comp)
  180. err = crypto_acomp_compress(fbreq);
  181. else
  182. err = crypto_acomp_decompress(fbreq);
  183. req->dlen = fbreq->dlen;
  184. return err;
  185. }
  186. static int acomp_do_one_req(struct acomp_req *req, bool comp)
  187. {
  188. if (acomp_request_isnondma(req))
  189. return acomp_do_nondma(req, comp);
  190. acomp_virt_to_sg(req);
  191. return comp ? crypto_acomp_reqtfm(req)->compress(req) :
  192. crypto_acomp_reqtfm(req)->decompress(req);
  193. }
  194. static int acomp_reqchain_finish(struct acomp_req *req, int err)
  195. {
  196. acomp_reqchain_virt(req);
  197. acomp_restore_req(req);
  198. return err;
  199. }
  200. static void acomp_reqchain_done(void *data, int err)
  201. {
  202. struct acomp_req *req = data;
  203. crypto_completion_t compl;
  204. compl = req->chain.compl;
  205. data = req->chain.data;
  206. if (err == -EINPROGRESS)
  207. goto notify;
  208. err = acomp_reqchain_finish(req, err);
  209. notify:
  210. compl(data, err);
  211. }
  212. static int acomp_do_req_chain(struct acomp_req *req, bool comp)
  213. {
  214. int err;
  215. acomp_save_req(req, acomp_reqchain_done);
  216. err = acomp_do_one_req(req, comp);
  217. if (err == -EBUSY || err == -EINPROGRESS)
  218. return err;
  219. return acomp_reqchain_finish(req, err);
  220. }
  221. int crypto_acomp_compress(struct acomp_req *req)
  222. {
  223. struct crypto_acomp *tfm = crypto_acomp_reqtfm(req);
  224. if (acomp_req_on_stack(req) && acomp_is_async(tfm))
  225. return -EAGAIN;
  226. if (crypto_acomp_req_virt(tfm) || acomp_request_issg(req))
  227. return crypto_acomp_reqtfm(req)->compress(req);
  228. return acomp_do_req_chain(req, true);
  229. }
  230. EXPORT_SYMBOL_GPL(crypto_acomp_compress);
  231. int crypto_acomp_decompress(struct acomp_req *req)
  232. {
  233. struct crypto_acomp *tfm = crypto_acomp_reqtfm(req);
  234. if (acomp_req_on_stack(req) && acomp_is_async(tfm))
  235. return -EAGAIN;
  236. if (crypto_acomp_req_virt(tfm) || acomp_request_issg(req))
  237. return crypto_acomp_reqtfm(req)->decompress(req);
  238. return acomp_do_req_chain(req, false);
  239. }
  240. EXPORT_SYMBOL_GPL(crypto_acomp_decompress);
  241. void comp_prepare_alg(struct comp_alg_common *alg)
  242. {
  243. struct crypto_alg *base = &alg->base;
  244. base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK;
  245. }
  246. int crypto_register_acomp(struct acomp_alg *alg)
  247. {
  248. struct crypto_alg *base = &alg->calg.base;
  249. comp_prepare_alg(&alg->calg);
  250. base->cra_type = &crypto_acomp_type;
  251. base->cra_flags |= CRYPTO_ALG_TYPE_ACOMPRESS;
  252. return crypto_register_alg(base);
  253. }
  254. EXPORT_SYMBOL_GPL(crypto_register_acomp);
  255. void crypto_unregister_acomp(struct acomp_alg *alg)
  256. {
  257. crypto_unregister_alg(&alg->base);
  258. }
  259. EXPORT_SYMBOL_GPL(crypto_unregister_acomp);
  260. int crypto_register_acomps(struct acomp_alg *algs, int count)
  261. {
  262. int i, ret;
  263. for (i = 0; i < count; i++) {
  264. ret = crypto_register_acomp(&algs[i]);
  265. if (ret) {
  266. crypto_unregister_acomps(algs, i);
  267. return ret;
  268. }
  269. }
  270. return 0;
  271. }
  272. EXPORT_SYMBOL_GPL(crypto_register_acomps);
  273. void crypto_unregister_acomps(struct acomp_alg *algs, int count)
  274. {
  275. int i;
  276. for (i = count - 1; i >= 0; --i)
  277. crypto_unregister_acomp(&algs[i]);
  278. }
  279. EXPORT_SYMBOL_GPL(crypto_unregister_acomps);
  280. static void acomp_stream_workfn(struct work_struct *work)
  281. {
  282. struct crypto_acomp_streams *s =
  283. container_of(work, struct crypto_acomp_streams, stream_work);
  284. struct crypto_acomp_stream __percpu *streams = s->streams;
  285. int cpu;
  286. for_each_cpu(cpu, &s->stream_want) {
  287. struct crypto_acomp_stream *ps;
  288. void *ctx;
  289. ps = per_cpu_ptr(streams, cpu);
  290. if (ps->ctx)
  291. continue;
  292. ctx = s->alloc_ctx();
  293. if (IS_ERR(ctx))
  294. break;
  295. spin_lock_bh(&ps->lock);
  296. ps->ctx = ctx;
  297. spin_unlock_bh(&ps->lock);
  298. cpumask_clear_cpu(cpu, &s->stream_want);
  299. }
  300. }
  301. void crypto_acomp_free_streams(struct crypto_acomp_streams *s)
  302. {
  303. struct crypto_acomp_stream __percpu *streams = s->streams;
  304. void (*free_ctx)(void *);
  305. int i;
  306. s->streams = NULL;
  307. if (!streams)
  308. return;
  309. cancel_work_sync(&s->stream_work);
  310. free_ctx = s->free_ctx;
  311. for_each_possible_cpu(i) {
  312. struct crypto_acomp_stream *ps = per_cpu_ptr(streams, i);
  313. if (!ps->ctx)
  314. continue;
  315. free_ctx(ps->ctx);
  316. }
  317. free_percpu(streams);
  318. }
  319. EXPORT_SYMBOL_GPL(crypto_acomp_free_streams);
  320. int crypto_acomp_alloc_streams(struct crypto_acomp_streams *s)
  321. {
  322. struct crypto_acomp_stream __percpu *streams;
  323. struct crypto_acomp_stream *ps;
  324. unsigned int i;
  325. void *ctx;
  326. if (s->streams)
  327. return 0;
  328. streams = alloc_percpu(struct crypto_acomp_stream);
  329. if (!streams)
  330. return -ENOMEM;
  331. ctx = s->alloc_ctx();
  332. if (IS_ERR(ctx)) {
  333. free_percpu(streams);
  334. return PTR_ERR(ctx);
  335. }
  336. i = cpumask_first(cpu_possible_mask);
  337. ps = per_cpu_ptr(streams, i);
  338. ps->ctx = ctx;
  339. for_each_possible_cpu(i) {
  340. ps = per_cpu_ptr(streams, i);
  341. spin_lock_init(&ps->lock);
  342. }
  343. s->streams = streams;
  344. INIT_WORK(&s->stream_work, acomp_stream_workfn);
  345. return 0;
  346. }
  347. EXPORT_SYMBOL_GPL(crypto_acomp_alloc_streams);
  348. struct crypto_acomp_stream *_crypto_acomp_lock_stream_bh(
  349. struct crypto_acomp_streams *s)
  350. {
  351. struct crypto_acomp_stream __percpu *streams = s->streams;
  352. int cpu = raw_smp_processor_id();
  353. struct crypto_acomp_stream *ps;
  354. ps = per_cpu_ptr(streams, cpu);
  355. spin_lock_bh(&ps->lock);
  356. if (likely(ps->ctx))
  357. return ps;
  358. spin_unlock(&ps->lock);
  359. cpumask_set_cpu(cpu, &s->stream_want);
  360. schedule_work(&s->stream_work);
  361. ps = per_cpu_ptr(streams, cpumask_first(cpu_possible_mask));
  362. spin_lock(&ps->lock);
  363. return ps;
  364. }
  365. EXPORT_SYMBOL_GPL(_crypto_acomp_lock_stream_bh);
  366. void acomp_walk_done_src(struct acomp_walk *walk, int used)
  367. {
  368. walk->slen -= used;
  369. if ((walk->flags & ACOMP_WALK_SRC_LINEAR))
  370. scatterwalk_advance(&walk->in, used);
  371. else
  372. scatterwalk_done_src(&walk->in, used);
  373. if ((walk->flags & ACOMP_WALK_SLEEP))
  374. cond_resched();
  375. }
  376. EXPORT_SYMBOL_GPL(acomp_walk_done_src);
  377. void acomp_walk_done_dst(struct acomp_walk *walk, int used)
  378. {
  379. walk->dlen -= used;
  380. if ((walk->flags & ACOMP_WALK_DST_LINEAR))
  381. scatterwalk_advance(&walk->out, used);
  382. else
  383. scatterwalk_done_dst(&walk->out, used);
  384. if ((walk->flags & ACOMP_WALK_SLEEP))
  385. cond_resched();
  386. }
  387. EXPORT_SYMBOL_GPL(acomp_walk_done_dst);
  388. int acomp_walk_next_src(struct acomp_walk *walk)
  389. {
  390. unsigned int slen = walk->slen;
  391. unsigned int max = UINT_MAX;
  392. if (!preempt_model_preemptible() && (walk->flags & ACOMP_WALK_SLEEP))
  393. max = PAGE_SIZE;
  394. if ((walk->flags & ACOMP_WALK_SRC_LINEAR)) {
  395. walk->in.__addr = (void *)(((u8 *)walk->in.sg) +
  396. walk->in.offset);
  397. return min(slen, max);
  398. }
  399. return slen ? scatterwalk_next(&walk->in, slen) : 0;
  400. }
  401. EXPORT_SYMBOL_GPL(acomp_walk_next_src);
  402. int acomp_walk_next_dst(struct acomp_walk *walk)
  403. {
  404. unsigned int dlen = walk->dlen;
  405. unsigned int max = UINT_MAX;
  406. if (!preempt_model_preemptible() && (walk->flags & ACOMP_WALK_SLEEP))
  407. max = PAGE_SIZE;
  408. if ((walk->flags & ACOMP_WALK_DST_LINEAR)) {
  409. walk->out.__addr = (void *)(((u8 *)walk->out.sg) +
  410. walk->out.offset);
  411. return min(dlen, max);
  412. }
  413. return dlen ? scatterwalk_next(&walk->out, dlen) : 0;
  414. }
  415. EXPORT_SYMBOL_GPL(acomp_walk_next_dst);
  416. int acomp_walk_virt(struct acomp_walk *__restrict walk,
  417. struct acomp_req *__restrict req, bool atomic)
  418. {
  419. struct scatterlist *src = req->src;
  420. struct scatterlist *dst = req->dst;
  421. walk->slen = req->slen;
  422. walk->dlen = req->dlen;
  423. if (!walk->slen || !walk->dlen)
  424. return -EINVAL;
  425. walk->flags = 0;
  426. if ((req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) && !atomic)
  427. walk->flags |= ACOMP_WALK_SLEEP;
  428. if ((req->base.flags & CRYPTO_ACOMP_REQ_SRC_VIRT))
  429. walk->flags |= ACOMP_WALK_SRC_LINEAR;
  430. if ((req->base.flags & CRYPTO_ACOMP_REQ_DST_VIRT))
  431. walk->flags |= ACOMP_WALK_DST_LINEAR;
  432. if ((walk->flags & ACOMP_WALK_SRC_LINEAR)) {
  433. walk->in.sg = (void *)req->svirt;
  434. walk->in.offset = 0;
  435. } else
  436. scatterwalk_start(&walk->in, src);
  437. if ((walk->flags & ACOMP_WALK_DST_LINEAR)) {
  438. walk->out.sg = (void *)req->dvirt;
  439. walk->out.offset = 0;
  440. } else
  441. scatterwalk_start(&walk->out, dst);
  442. return 0;
  443. }
  444. EXPORT_SYMBOL_GPL(acomp_walk_virt);
  445. struct acomp_req *acomp_request_clone(struct acomp_req *req,
  446. size_t total, gfp_t gfp)
  447. {
  448. struct acomp_req *nreq;
  449. nreq = container_of(crypto_request_clone(&req->base, total, gfp),
  450. struct acomp_req, base);
  451. if (nreq == req)
  452. return req;
  453. if (req->src == &req->chain.ssg)
  454. nreq->src = &nreq->chain.ssg;
  455. if (req->dst == &req->chain.dsg)
  456. nreq->dst = &nreq->chain.dsg;
  457. return nreq;
  458. }
  459. EXPORT_SYMBOL_GPL(acomp_request_clone);
  460. MODULE_LICENSE("GPL");
  461. MODULE_DESCRIPTION("Asynchronous compression type");