Commit 9c8cf582 authored by Herbert Xu's avatar Herbert Xu
Browse files

crypto: acomp - Add acomp_walk



Add acomp_walk which is similar to skcipher_walk but tailored for
acomp.

Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 42d9f6c7
Loading
Loading
Loading
Loading
+116 −0
Original line number Diff line number Diff line
@@ -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");
+44 −0
Original line number Diff line number Diff line
@@ -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