summaryrefslogtreecommitdiff
path: root/crypto/acompress.c
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2025-03-19 14:04:54 +0800
committerHerbert Xu <herbert@gondor.apana.org.au>2025-04-07 13:22:25 +0800
commit9c8cf582626ef56632006212b385cfbb6c54f094 (patch)
tree9ec4aaad5f729e4e270662b539d936f81a6620a6 /crypto/acompress.c
parent42d9f6c774790d290c175e8775ce9f1366438098 (diff)
crypto: acomp - Add acomp_walk
Add acomp_walk which is similar to skcipher_walk but tailored for acomp. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto/acompress.c')
-rw-r--r--crypto/acompress.c116
1 files changed, 116 insertions, 0 deletions
diff --git a/crypto/acompress.c b/crypto/acompress.c
index 2cf5e9d749cf..70bc1fd044e4 100644
--- a/crypto/acompress.c
+++ b/crypto/acompress.c
@@ -8,6 +8,7 @@
*/
#include <crypto/internal/acompress.h>
+#include <crypto/scatterwalk.h>
#include <linux/cryptouser.h>
#include <linux/cpumask.h>
#include <linux/errno.h>
@@ -15,6 +16,8 @@
#include <linux/module.h>
#include <linux/page-flags.h>
#include <linux/percpu.h>
+#include <linux/scatterlist.h>
+#include <linux/sched.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/smp.h>
@@ -27,6 +30,14 @@
struct crypto_scomp;
+enum {
+ ACOMP_WALK_SLEEP = 1 << 0,
+ ACOMP_WALK_SRC_LINEAR = 1 << 1,
+ ACOMP_WALK_SRC_FOLIO = 1 << 2,
+ ACOMP_WALK_DST_LINEAR = 1 << 3,
+ ACOMP_WALK_DST_FOLIO = 1 << 4,
+};
+
static const struct crypto_type crypto_acomp_type;
static void acomp_reqchain_done(void *data, int err);
@@ -546,5 +557,110 @@ struct crypto_acomp_stream *crypto_acomp_lock_stream_bh(
}
EXPORT_SYMBOL_GPL(crypto_acomp_lock_stream_bh);
+void acomp_walk_done_src(struct acomp_walk *walk, int used)
+{
+ walk->slen -= used;
+ if ((walk->flags & ACOMP_WALK_SRC_LINEAR))
+ scatterwalk_advance(&walk->in, used);
+ else
+ scatterwalk_done_src(&walk->in, used);
+
+ if ((walk->flags & ACOMP_WALK_SLEEP))
+ cond_resched();
+}
+EXPORT_SYMBOL_GPL(acomp_walk_done_src);
+
+void acomp_walk_done_dst(struct acomp_walk *walk, int used)
+{
+ walk->dlen -= used;
+ if ((walk->flags & ACOMP_WALK_DST_LINEAR))
+ scatterwalk_advance(&walk->out, used);
+ else
+ scatterwalk_done_dst(&walk->out, used);
+
+ if ((walk->flags & ACOMP_WALK_SLEEP))
+ cond_resched();
+}
+EXPORT_SYMBOL_GPL(acomp_walk_done_dst);
+
+int acomp_walk_next_src(struct acomp_walk *walk)
+{
+ unsigned int slen = walk->slen;
+ unsigned int max = UINT_MAX;
+
+ if (!preempt_model_preemptible() && (walk->flags & ACOMP_WALK_SLEEP))
+ max = PAGE_SIZE;
+ if ((walk->flags & ACOMP_WALK_SRC_LINEAR)) {
+ walk->in.__addr = (void *)(((u8 *)walk->in.sg) +
+ walk->in.offset);
+ return min(slen, max);
+ }
+
+ return slen ? scatterwalk_next(&walk->in, slen) : 0;
+}
+EXPORT_SYMBOL_GPL(acomp_walk_next_src);
+
+int acomp_walk_next_dst(struct acomp_walk *walk)
+{
+ unsigned int dlen = walk->dlen;
+ unsigned int max = UINT_MAX;
+
+ if (!preempt_model_preemptible() && (walk->flags & ACOMP_WALK_SLEEP))
+ max = PAGE_SIZE;
+ if ((walk->flags & ACOMP_WALK_DST_LINEAR)) {
+ walk->out.__addr = (void *)(((u8 *)walk->out.sg) +
+ walk->out.offset);
+ return min(dlen, max);
+ }
+
+ return dlen ? scatterwalk_next(&walk->out, dlen) : 0;
+}
+EXPORT_SYMBOL_GPL(acomp_walk_next_dst);
+
+int acomp_walk_virt(struct acomp_walk *__restrict walk,
+ struct acomp_req *__restrict req)
+{
+ struct scatterlist *src = req->src;
+ struct scatterlist *dst = req->dst;
+
+ walk->slen = req->slen;
+ walk->dlen = req->dlen;
+
+ if (!walk->slen || !walk->dlen)
+ return -EINVAL;
+
+ walk->flags = 0;
+ if ((req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP))
+ walk->flags |= ACOMP_WALK_SLEEP;
+ if ((req->base.flags & CRYPTO_ACOMP_REQ_SRC_VIRT))
+ walk->flags |= ACOMP_WALK_SRC_LINEAR;
+ else if ((req->base.flags & CRYPTO_ACOMP_REQ_SRC_FOLIO)) {
+ src = &req->chain.ssg;
+ sg_init_table(src, 1);
+ sg_set_folio(src, req->sfolio, walk->slen, req->soff);
+ }
+ if ((req->base.flags & CRYPTO_ACOMP_REQ_DST_VIRT))
+ walk->flags |= ACOMP_WALK_DST_LINEAR;
+ else if ((req->base.flags & CRYPTO_ACOMP_REQ_DST_FOLIO)) {
+ dst = &req->chain.dsg;
+ sg_init_table(dst, 1);
+ sg_set_folio(dst, req->dfolio, walk->dlen, req->doff);
+ }
+
+ if ((walk->flags & ACOMP_WALK_SRC_LINEAR)) {
+ walk->in.sg = (void *)req->svirt;
+ walk->in.offset = 0;
+ } else
+ scatterwalk_start(&walk->in, src);
+ if ((walk->flags & ACOMP_WALK_DST_LINEAR)) {
+ walk->out.sg = (void *)req->dvirt;
+ walk->out.offset = 0;
+ } else
+ scatterwalk_start(&walk->out, dst);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(acomp_walk_virt);
+
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Asynchronous compression type");