Commit 3d72ad46 authored by Herbert Xu's avatar Herbert Xu
Browse files

crypto: acomp - Move stream management into scomp layer



Rather than allocating the stream memory in the request object,
move it into a per-cpu buffer managed by scomp.  This takes the
stress off the user from having to manage large request objects
and setting up their own per-cpu buffers in order to do so.

Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 0af7304c
Loading
Loading
Loading
Loading
+0 −30
Original line number Diff line number Diff line
@@ -123,36 +123,6 @@ struct crypto_acomp *crypto_alloc_acomp_node(const char *alg_name, u32 type,
}
EXPORT_SYMBOL_GPL(crypto_alloc_acomp_node);

struct acomp_req *acomp_request_alloc(struct crypto_acomp *acomp)
{
	struct crypto_tfm *tfm = crypto_acomp_tfm(acomp);
	struct acomp_req *req;

	req = __acomp_request_alloc(acomp);
	if (req && (tfm->__crt_alg->cra_type != &crypto_acomp_type))
		return crypto_acomp_scomp_alloc_ctx(req);

	return req;
}
EXPORT_SYMBOL_GPL(acomp_request_alloc);

void acomp_request_free(struct acomp_req *req)
{
	struct crypto_acomp *acomp = crypto_acomp_reqtfm(req);
	struct crypto_tfm *tfm = crypto_acomp_tfm(acomp);

	if (tfm->__crt_alg->cra_type != &crypto_acomp_type)
		crypto_acomp_scomp_free_ctx(req);

	if (req->base.flags & CRYPTO_ACOMP_ALLOC_OUTPUT) {
		acomp->dst_free(req->dst);
		req->dst = NULL;
	}

	__acomp_request_free(req);
}
EXPORT_SYMBOL_GPL(acomp_request_free);

void comp_prepare_alg(struct comp_alg_common *alg)
{
	struct crypto_alg *base = &alg->base;
+0 −2
Original line number Diff line number Diff line
@@ -15,8 +15,6 @@ struct acomp_req;
struct comp_alg_common;

int crypto_init_scomp_ops_async(struct crypto_tfm *tfm);
struct acomp_req *crypto_acomp_scomp_alloc_ctx(struct acomp_req *req);
void crypto_acomp_scomp_free_ctx(struct acomp_req *req);

void comp_prepare_alg(struct comp_alg_common *alg);

+58 −32
Original line number Diff line number Diff line
@@ -98,13 +98,62 @@ static int crypto_scomp_alloc_scratches(void)
	return -ENOMEM;
}

static void scomp_free_streams(struct scomp_alg *alg)
{
	struct crypto_acomp_stream __percpu *stream = alg->stream;
	int i;

	for_each_possible_cpu(i) {
		struct crypto_acomp_stream *ps = per_cpu_ptr(stream, i);

		if (!ps->ctx)
			break;

		alg->free_ctx(ps);
	}

	free_percpu(stream);
}

static int scomp_alloc_streams(struct scomp_alg *alg)
{
	struct crypto_acomp_stream __percpu *stream;
	int i;

	stream = alloc_percpu(struct crypto_acomp_stream);
	if (!stream)
		return -ENOMEM;

	for_each_possible_cpu(i) {
		struct crypto_acomp_stream *ps = per_cpu_ptr(stream, i);

		ps->ctx = alg->alloc_ctx();
		if (IS_ERR(ps->ctx)) {
			scomp_free_streams(alg);
			return PTR_ERR(ps->ctx);
		}

		spin_lock_init(&ps->lock);
	}

	alg->stream = stream;
	return 0;
}

static int crypto_scomp_init_tfm(struct crypto_tfm *tfm)
{
	struct scomp_alg *alg = crypto_scomp_alg(__crypto_scomp_tfm(tfm));
	int ret = 0;

	mutex_lock(&scomp_lock);
	if (!alg->stream) {
		ret = scomp_alloc_streams(alg);
		if (ret)
			goto unlock;
	}
	if (!scomp_scratch_users++)
		ret = crypto_scomp_alloc_scratches();
unlock:
	mutex_unlock(&scomp_lock);

	return ret;
@@ -115,7 +164,7 @@ static int scomp_acomp_comp_decomp(struct acomp_req *req, int dir)
	struct crypto_acomp *tfm = crypto_acomp_reqtfm(req);
	void **tfm_ctx = acomp_tfm_ctx(tfm);
	struct crypto_scomp *scomp = *tfm_ctx;
	void **ctx = acomp_request_ctx(req);
	struct crypto_acomp_stream *stream;
	struct scomp_scratch *scratch;
	void *src, *dst;
	unsigned int dlen;
@@ -148,12 +197,15 @@ static int scomp_acomp_comp_decomp(struct acomp_req *req, int dir)
	else
		dst = scratch->dst;

	stream = raw_cpu_ptr(crypto_scomp_alg(scomp)->stream);
	spin_lock(&stream->lock);
	if (dir)
		ret = crypto_scomp_compress(scomp, src, req->slen,
					    dst, &req->dlen, *ctx);
					    dst, &req->dlen, stream->ctx);
	else
		ret = crypto_scomp_decompress(scomp, src, req->slen,
					      dst, &req->dlen, *ctx);
					      dst, &req->dlen, stream->ctx);
	spin_unlock(&stream->lock);
	if (!ret) {
		if (!req->dst) {
			req->dst = sgl_alloc(req->dlen, GFP_ATOMIC, NULL);
@@ -226,45 +278,19 @@ int crypto_init_scomp_ops_async(struct crypto_tfm *tfm)
	crt->compress = scomp_acomp_compress;
	crt->decompress = scomp_acomp_decompress;
	crt->dst_free = sgl_free;
	crt->reqsize = sizeof(void *);

	return 0;
}

struct acomp_req *crypto_acomp_scomp_alloc_ctx(struct acomp_req *req)
{
	struct crypto_acomp *acomp = crypto_acomp_reqtfm(req);
	struct crypto_tfm *tfm = crypto_acomp_tfm(acomp);
	struct crypto_scomp **tfm_ctx = crypto_tfm_ctx(tfm);
	struct crypto_scomp *scomp = *tfm_ctx;
	void *ctx;

	ctx = crypto_scomp_alloc_ctx(scomp);
	if (IS_ERR(ctx)) {
		kfree(req);
		return NULL;
	}

	*req->__ctx = ctx;

	return req;
}

void crypto_acomp_scomp_free_ctx(struct acomp_req *req)
static void crypto_scomp_destroy(struct crypto_alg *alg)
{
	struct crypto_acomp *acomp = crypto_acomp_reqtfm(req);
	struct crypto_tfm *tfm = crypto_acomp_tfm(acomp);
	struct crypto_scomp **tfm_ctx = crypto_tfm_ctx(tfm);
	struct crypto_scomp *scomp = *tfm_ctx;
	void *ctx = *req->__ctx;

	if (ctx)
		crypto_scomp_free_ctx(scomp, ctx);
	scomp_free_streams(__crypto_scomp_alg(alg));
}

static const struct crypto_type crypto_scomp_type = {
	.extsize = crypto_alg_extsize,
	.init_tfm = crypto_scomp_init_tfm,
	.destroy = crypto_scomp_destroy,
#ifdef CONFIG_PROC_FS
	.show = crypto_scomp_show,
#endif
+24 −2
Original line number Diff line number Diff line
@@ -10,8 +10,12 @@
#define _CRYPTO_ACOMP_H

#include <linux/atomic.h>
#include <linux/compiler_types.h>
#include <linux/container_of.h>
#include <linux/crypto.h>
#include <linux/slab.h>
#include <linux/spinlock_types.h>
#include <linux/types.h>

#define CRYPTO_ACOMP_ALLOC_OUTPUT	0x00000001
#define CRYPTO_ACOMP_DST_MAX		131072
@@ -54,8 +58,14 @@ struct crypto_acomp {
	struct crypto_tfm base;
};

struct crypto_acomp_stream {
	spinlock_t lock;
	void *ctx;
};

#define COMP_ALG_COMMON {			\
	struct crypto_alg base;			\
	struct crypto_acomp_stream __percpu *stream;	\
}
struct comp_alg_common COMP_ALG_COMMON;

@@ -173,7 +183,16 @@ static inline int crypto_has_acomp(const char *alg_name, u32 type, u32 mask)
 *
 * Return:	allocated handle in case of success or NULL in case of an error
 */
struct acomp_req *acomp_request_alloc(struct crypto_acomp *tfm);
static inline struct acomp_req *acomp_request_alloc_noprof(struct crypto_acomp *tfm)
{
	struct acomp_req *req;

	req = kzalloc_noprof(sizeof(*req) + crypto_acomp_reqsize(tfm), GFP_KERNEL);
	if (likely(req))
		acomp_request_set_tfm(req, tfm);
	return req;
}
#define acomp_request_alloc(...)	alloc_hooks(acomp_request_alloc_noprof(__VA_ARGS__))

/**
 * acomp_request_free() -- zeroize and free asynchronous (de)compression
@@ -182,7 +201,10 @@ struct acomp_req *acomp_request_alloc(struct crypto_acomp *tfm);
 *
 * @req:	request to free
 */
void acomp_request_free(struct acomp_req *req);
static inline void acomp_request_free(struct acomp_req *req)
{
	kfree_sensitive(req);
}

/**
 * acomp_request_set_callback() -- Sets an asynchronous callback
+1 −16
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@
 *
 * @reqsize:	Context size for (de)compression requests
 * @base:	Common crypto API algorithm data structure
 * @stream:	Per-cpu memory for algorithm
 * @calg:	Cmonn algorithm data structure shared with scomp
 */
struct acomp_alg {
@@ -68,22 +69,6 @@ static inline void acomp_request_complete(struct acomp_req *req,
	crypto_request_complete(&req->base, err);
}

static inline struct acomp_req *__acomp_request_alloc_noprof(struct crypto_acomp *tfm)
{
	struct acomp_req *req;

	req = kzalloc_noprof(sizeof(*req) + crypto_acomp_reqsize(tfm), GFP_KERNEL);
	if (likely(req))
		acomp_request_set_tfm(req, tfm);
	return req;
}
#define __acomp_request_alloc(...)	alloc_hooks(__acomp_request_alloc_noprof(__VA_ARGS__))

static inline void __acomp_request_free(struct acomp_req *req)
{
	kfree_sensitive(req);
}

/**
 * crypto_register_acomp() -- Register asynchronous compression algorithm
 *
Loading