crypto: acomp - Add acomp_walk
authorHerbert Xu <herbert@gondor.apana.org.au>
Wed, 19 Mar 2025 06:04:54 +0000 (14:04 +0800)
committerHerbert Xu <herbert@gondor.apana.org.au>
Mon, 7 Apr 2025 05:22:25 +0000 (13:22 +0800)
Add acomp_walk which is similar to skcipher_walk but tailored for
acomp.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
crypto/acompress.c
include/crypto/internal/acompress.h

index 2cf5e9d749cf4fdb2e1f588c65d1257e7504ea81..70bc1fd044e446290908bbcbf2fbcc08dd774936 100644 (file)
@@ -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>
 
 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");
index ee5eff19eaf4e3d7cc42b9741b8ee44048b48285..fbbff9a8a2d989ae62dde2d622ec780d8b03fd57 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <crypto/acompress.h>
 #include <crypto/algapi.h>
+#include <crypto/scatterwalk.h>
 #include <linux/compiler_types.h>
 #include <linux/cpumask_types.h>
 #include <linux/spinlock.h>
@@ -75,6 +76,37 @@ struct crypto_acomp_streams {
        cpumask_t stream_want;
 };
 
+struct acomp_walk {
+       union {
+               /* Virtual address of the source. */
+               struct {
+                       struct {
+                               const void *const addr;
+                       } virt;
+               } src;
+
+               /* Private field for the API, do not use. */
+               struct scatter_walk in;
+       };
+
+       union {
+               /* Virtual address of the destination. */
+               struct {
+                       struct {
+                               void *const addr;
+                       } virt;
+               } dst;
+
+               /* Private field for the API, do not use. */
+               struct scatter_walk out;
+       };
+
+       unsigned int slen;
+       unsigned int dlen;
+
+       int flags;
+};
+
 /*
  * Transform internal helpers.
  */
@@ -190,4 +222,16 @@ static inline void crypto_acomp_unlock_stream_bh(
 {
        spin_unlock_bh(&stream->lock);
 }
+
+void acomp_walk_done_src(struct acomp_walk *walk, int used);
+void acomp_walk_done_dst(struct acomp_walk *walk, int used);
+int acomp_walk_next_src(struct acomp_walk *walk);
+int acomp_walk_next_dst(struct acomp_walk *walk);
+int acomp_walk_virt(struct acomp_walk *__restrict walk,
+                   struct acomp_req *__restrict req);
+
+static inline bool acomp_walk_more_src(const struct acomp_walk *walk, int cur)
+{
+       return walk->slen != cur;
+}
 #endif