Subject: [RFC PATCH 04/21] net: ipcomp: Migrate to acomp API from deprecated comp API

From: Ard Biesheuvel <[email-masked]>
Date: Tue, 18 Jul 2023 14:58:30 +0200

Migrate the IPcomp network compression code to the acomp API, in order
to drop the dependency on the obsolete 'comp' API which is going away.

For the time being, this is a rather mechanical conversion replacing
each comp TFM object with an acomp TFM/request object pair - this is
necessary because, at this point, there is still a 1:1 relation between
acomp tranforms and requests in the acomp-to-scomp adaptation layer, and
this deviates from the model used by AEADs and skciphers where the TFM
is fully reentrant, and operations using the same encryption keys can be
issued in parallel using individual request objects but the same TFM.

Also, this minimal conversion does not yet take advantage of the fact
that the acomp API takes scatterlists as input and output descriptors,
which in principle removes the need to linearize the SKBs. However,
given that compression code generally requires in- and output buffers to
be non-overlapping, scratch buffers will always be needed, and so
whether this conversion is worth while is TBD.

Signed-off-by: Ard Biesheuvel <[email-masked]>
---
 include/crypto/acompress.h |   5 +
 include/net/ipcomp.h       |   4 +-
 net/xfrm/xfrm_algo.c       |   7 +-
 net/xfrm/xfrm_ipcomp.c     | 107 +++++++++++++-------
 4 files changed, 79 insertions(+), 44 deletions(-)

diff --git a/include/crypto/acompress.h b/include/crypto/acompress.h
index ccb6f3279bc8b32e..3f54e3d8815a9d0d 100644
--- a/include/crypto/acompress.h
+++ b/include/crypto/acompress.h
@@ -318,4 +318,9 @@ static inline int crypto_acomp_decompress(struct acomp_req *req)
 	return crypto_comp_errstat(alg, tfm->decompress(req));
 }
 
+static inline const char *crypto_acomp_name(struct crypto_acomp *acomp)
+{
+       return crypto_tfm_alg_name(crypto_acomp_tfm(acomp));
+}
+
 #endif
diff --git a/include/net/ipcomp.h b/include/net/ipcomp.h
index 8660a2a6d1fc76a7..bf27ac7e3ca952e2 100644
--- a/include/net/ipcomp.h
+++ b/include/net/ipcomp.h
@@ -7,12 +7,12 @@
 
 #define IPCOMP_SCRATCH_SIZE     65400
 
-struct crypto_comp;
+struct acomp_req;
 struct ip_comp_hdr;
 
 struct ipcomp_data {
 	u16 threshold;
-	struct crypto_comp * __percpu *tfms;
+	struct acomp_req * __percpu *reqs;
 };
 
 struct ip_comp_hdr;
diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c
index 094734fbec967505..ca411bcebc53ad4f 100644
--- a/net/xfrm/xfrm_algo.c
+++ b/net/xfrm/xfrm_algo.c
@@ -5,6 +5,7 @@
  * Copyright (c) 2002 James Morris <[email-masked]>
  */
 
+#include <crypto/acompress.h>
 #include <crypto/hash.h>
 #include <crypto/skcipher.h>
 #include <linux/module.h>
@@ -674,7 +675,7 @@ static const struct xfrm_algo_list xfrm_ealg_list = {
 static const struct xfrm_algo_list xfrm_calg_list = {
 	.algs = calg_list,
 	.entries = ARRAY_SIZE(calg_list),
-	.type = CRYPTO_ALG_TYPE_COMPRESS,
+	.type = CRYPTO_ALG_TYPE_ACOMPRESS,
 	.mask = CRYPTO_ALG_TYPE_MASK,
 };
 
@@ -833,8 +834,8 @@ void xfrm_probe_algs(void)
 	}
 
 	for (i = 0; i < calg_entries(); i++) {
-		status = crypto_has_comp(calg_list[i].name, 0,
-					 CRYPTO_ALG_ASYNC);
+		status = crypto_has_acomp(calg_list[i].name, 0,
+					  CRYPTO_ALG_ASYNC);
 		if (calg_list[i].available != status)
 			calg_list[i].available = status;
 	}
diff --git a/net/xfrm/xfrm_ipcomp.c b/net/xfrm/xfrm_ipcomp.c
index 9c0fa0e1786a2d42..e29ef55e0f01d144 100644
--- a/net/xfrm/xfrm_ipcomp.c
+++ b/net/xfrm/xfrm_ipcomp.c
@@ -20,20 +20,21 @@
 #include <linux/slab.h>
 #include <linux/smp.h>
 #include <linux/vmalloc.h>
+#include <crypto/acompress.h>
 #include <net/ip.h>
 #include <net/ipcomp.h>
 #include <net/xfrm.h>
 
-struct ipcomp_tfms {
+struct ipcomp_reqs {
 	struct list_head list;
-	struct crypto_comp * __percpu *tfms;
+	struct acomp_req * __percpu *reqs;
 	int users;
 };
 
 static DEFINE_MUTEX(ipcomp_resource_mutex);
 static void * __percpu *ipcomp_scratches;
 static int ipcomp_scratch_users;
-static LIST_HEAD(ipcomp_tfms_list);
+static LIST_HEAD(ipcomp_reqs_list);
 
 static int ipcomp_decompress(struct xfrm_state *x, struct sk_buff *skb)
 {
@@ -42,13 +43,19 @@ static int ipcomp_decompress(struct xfrm_state *x, struct sk_buff *skb)
 	int dlen = IPCOMP_SCRATCH_SIZE;
 	const u8 *start = skb->data;
 	u8 *scratch = *this_cpu_ptr(ipcomp_scratches);
-	struct crypto_comp *tfm = *this_cpu_ptr(ipcd->tfms);
-	int err = crypto_comp_decompress(tfm, start, plen, scratch, &dlen);
-	int len;
+	struct acomp_req *req = *this_cpu_ptr(ipcd->reqs);
+	struct scatterlist sg_in, sg_out;
+	int err, len;
 
+	sg_init_one(&sg_in, start, plen);
+	sg_init_one(&sg_out, scratch, dlen);
+	acomp_request_set_params(req, &sg_in, &sg_out, plen, dlen);
+
+	err = crypto_acomp_decompress(req);
 	if (err)
 		return err;
 
+	dlen = req->dlen;
 	if (dlen < (plen + sizeof(struct ip_comp_hdr)))
 		return -EINVAL;
 
@@ -125,17 +132,24 @@ static int ipcomp_compress(struct xfrm_state *x, struct sk_buff *skb)
 	const int plen = skb->len;
 	int dlen = IPCOMP_SCRATCH_SIZE;
 	u8 *start = skb->data;
-	struct crypto_comp *tfm;
+	struct acomp_req *req = *this_cpu_ptr(ipcd->reqs);
+	struct scatterlist sg_in, sg_out;
 	u8 *scratch;
 	int err;
 
 	local_bh_disable();
 	scratch = *this_cpu_ptr(ipcomp_scratches);
-	tfm = *this_cpu_ptr(ipcd->tfms);
-	err = crypto_comp_compress(tfm, start, plen, scratch, &dlen);
+	req = *this_cpu_ptr(ipcd->reqs);
+
+	sg_init_one(&sg_in, start, plen);
+	sg_init_one(&sg_out, scratch, dlen);
+	acomp_request_set_params(req, &sg_in, &sg_out, plen, dlen);
+
+	err = crypto_acomp_compress(req);
 	if (err)
 		goto out;
 
+	dlen = req->dlen;
 	if ((dlen + sizeof(struct ip_comp_hdr)) >= plen) {
 		err = -EMSGSIZE;
 		goto out;
@@ -229,17 +243,17 @@ static void * __percpu *ipcomp_alloc_scratches(void)
 	return scratches;
 }
 
-static void ipcomp_free_tfms(struct crypto_comp * __percpu *tfms)
+static void ipcomp_free_reqs(struct acomp_req * __percpu *reqs)
 {
-	struct ipcomp_tfms *pos;
+	struct ipcomp_reqs *pos;
 	int cpu;
 
-	list_for_each_entry(pos, &ipcomp_tfms_list, list) {
-		if (pos->tfms == tfms)
+	list_for_each_entry(pos, &ipcomp_reqs_list, list) {
+		if (pos->reqs == reqs)
 			break;
 	}
 
-	WARN_ON(list_entry_is_head(pos, &ipcomp_tfms_list, list));
+	WARN_ON(list_entry_is_head(pos, &ipcomp_reqs_list, list));
 
 	if (--pos->users)
 		return;
@@ -247,32 +261,39 @@ static void ipcomp_free_tfms(struct crypto_comp * __percpu *tfms)
 	list_del(&pos->list);
 	kfree(pos);
 
-	if (!tfms)
+	if (!reqs)
 		return;
 
 	for_each_possible_cpu(cpu) {
-		struct crypto_comp *tfm = *per_cpu_ptr(tfms, cpu);
-		crypto_free_comp(tfm);
+		struct acomp_req *req = *per_cpu_ptr(reqs, cpu);
+
+		if (req) {
+			struct crypto_acomp *acomp = crypto_acomp_reqtfm(req);
+
+			acomp_request_free(req);
+			crypto_free_acomp(acomp);
+		}
 	}
-	free_percpu(tfms);
+	free_percpu(reqs);
 }
 
-static struct crypto_comp * __percpu *ipcomp_alloc_tfms(const char *alg_name)
+static struct acomp_req * __percpu *ipcomp_alloc_reqs(const char *alg_name)
 {
-	struct ipcomp_tfms *pos;
-	struct crypto_comp * __percpu *tfms;
+	struct ipcomp_reqs *pos;
+	struct crypto_acomp *acomp;
+	struct acomp_req * __percpu *reqs;
 	int cpu;

-	list_for_each_entry(pos, &ipcomp_tfms_list, list) {
-		struct crypto_comp *tfm;
+	list_for_each_entry(pos, &ipcomp_reqs_list, list) {
+		struct crypto_acomp *tfm;
 
 		/* This can be any valid CPU ID so we don't need locking. */
-		tfm = this_cpu_read(*pos->tfms);
+		tfm = crypto_acomp_reqtfm(this_cpu_read(*pos->reqs));
 
-		if (!strcmp(crypto_comp_name(tfm), alg_name)) {
+		if (!strcmp(crypto_acomp_name(tfm), alg_name)) {
 			pos->users++;
-			return pos->tfms;
+			return pos->reqs;
 		}
 	}
 
@@ -282,31 +303,39 @@ static struct crypto_comp * __percpu *ipcomp_alloc_tfms(const char *alg_name)
 
 	pos->users = 1;
 	INIT_LIST_HEAD(&pos->list);
-	list_add(&pos->list, &ipcomp_tfms_list);
+	list_add(&pos->list, &ipcomp_reqs_list);
 
-	pos->tfms = tfms = alloc_percpu(struct crypto_comp *);
-	if (!tfms)
+	reqs = alloc_percpu_gfp(struct acomp_req *, GFP_KERNEL | __GFP_ZERO);
+	if (!reqs)
 		goto error;
 
 	for_each_possible_cpu(cpu) {
-		struct crypto_comp *tfm = crypto_alloc_comp(alg_name, 0,
-							    CRYPTO_ALG_ASYNC);
-		if (IS_ERR(tfm))
+		struct acomp_req *req;
+
+		acomp = crypto_alloc_acomp(alg_name, 0, CRYPTO_ALG_ASYNC);
+		if (IS_ERR(acomp))
 			goto error;
-		*per_cpu_ptr(tfms, cpu) = tfm;
+
+		req = acomp_request_alloc(acomp);
+		if (!req) {
+			crypto_free_acomp(acomp);
+			goto error;
+		}
+		*per_cpu_ptr(reqs, cpu) = req;
 	}
 
-	return tfms;
+	pos->reqs = reqs;
+	return reqs;
 
 error:
-	ipcomp_free_tfms(tfms);
+	ipcomp_free_reqs(reqs);
 	return NULL;
 }
 
 static void ipcomp_free_data(struct ipcomp_data *ipcd)
 {
-	if (ipcd->tfms)
-		ipcomp_free_tfms(ipcd->tfms);
+	if (ipcd->reqs)
+		ipcomp_free_reqs(ipcd->reqs);
 	ipcomp_free_scratches();
 }
 
@@ -349,8 +378,8 @@ int ipcomp_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack)
 	if (!ipcomp_alloc_scratches())
 		goto error;
 
-	ipcd->tfms = ipcomp_alloc_tfms(x->calg->alg_name);
-	if (!ipcd->tfms)
+	ipcd->reqs = ipcomp_alloc_reqs(x->calg->alg_name);
+	if (!ipcd->reqs)
 		goto error;
 	mutex_unlock(&ipcomp_resource_mutex);
 
-- 
2.39.2