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>
This commit is contained in:
Herbert Xu 2025-03-19 14:04:54 +08:00
parent 42d9f6c774
commit 9c8cf58262
2 changed files with 160 additions and 0 deletions

View 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>
@ -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");

View 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