]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
crypto: acomp - Add ACOMP_REQUEST_ALLOC and acomp_request_alloc_extra
authorHerbert Xu <herbert@gondor.apana.org.au>
Sat, 15 Mar 2025 10:30:34 +0000 (18:30 +0800)
committerHerbert Xu <herbert@gondor.apana.org.au>
Fri, 21 Mar 2025 09:33:39 +0000 (17:33 +0800)
Add ACOMP_REQUEST_ALLOC which is a wrapper around acomp_request_alloc
that falls back to a synchronous stack reqeust if the allocation
fails.

Also add ACOMP_REQUEST_ON_STACK which stores the request on the stack
only.

The request should be freed with acomp_request_free.

Finally add acomp_request_alloc_extra which gives the user extra
memory to use in conjunction with the request.

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

index 194a4b36f97fde7454382e49dcd4f4d64dbc000a..9da033ded193ee757423fc0ded2569608bfca6b4 100644 (file)
@@ -60,28 +60,56 @@ static void crypto_acomp_exit_tfm(struct crypto_tfm *tfm)
        struct crypto_acomp *acomp = __crypto_acomp_tfm(tfm);
        struct acomp_alg *alg = crypto_acomp_alg(acomp);
 
-       alg->exit(acomp);
+       if (alg->exit)
+               alg->exit(acomp);
+
+       if (acomp_is_async(acomp))
+               crypto_free_acomp(acomp->fb);
 }
 
 static int crypto_acomp_init_tfm(struct crypto_tfm *tfm)
 {
        struct crypto_acomp *acomp = __crypto_acomp_tfm(tfm);
        struct acomp_alg *alg = crypto_acomp_alg(acomp);
+       struct crypto_acomp *fb = NULL;
+       int err;
+
+       acomp->fb = acomp;
 
        if (tfm->__crt_alg->cra_type != &crypto_acomp_type)
                return crypto_init_scomp_ops_async(tfm);
 
+       if (acomp_is_async(acomp)) {
+               fb = crypto_alloc_acomp(crypto_acomp_alg_name(acomp), 0,
+                                       CRYPTO_ALG_ASYNC);
+               if (IS_ERR(fb))
+                       return PTR_ERR(fb);
+
+               err = -EINVAL;
+               if (crypto_acomp_reqsize(fb) > MAX_SYNC_COMP_REQSIZE)
+                       goto out_free_fb;
+
+               acomp->fb = fb;
+       }
+
        acomp->compress = alg->compress;
        acomp->decompress = alg->decompress;
        acomp->reqsize = alg->reqsize;
 
-       if (alg->exit)
-               acomp->base.exit = crypto_acomp_exit_tfm;
+       acomp->base.exit = crypto_acomp_exit_tfm;
 
-       if (alg->init)
-               return alg->init(acomp);
+       if (!alg->init)
+               return 0;
+
+       err = alg->init(acomp);
+       if (err)
+               goto out_free_fb;
 
        return 0;
+
+out_free_fb:
+       crypto_free_acomp(fb);
+       return err;
 }
 
 static unsigned int crypto_acomp_extsize(struct crypto_alg *alg)
index 53c9e632862b4b212f3dd53d7aeb13bdc1f0bbb6..03cb381c2c547ae8fe9714bde58f63719faf228e 100644 (file)
 #define _CRYPTO_ACOMP_H
 
 #include <linux/atomic.h>
+#include <linux/args.h>
 #include <linux/compiler_types.h>
 #include <linux/container_of.h>
 #include <linux/crypto.h>
+#include <linux/err.h>
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
 #include <linux/spinlock_types.h>
 
 #define CRYPTO_ACOMP_DST_MAX           131072
 
+#define        MAX_SYNC_COMP_REQSIZE           0
+
+#define ACOMP_REQUEST_ALLOC(name, tfm, gfp) \
+        char __##name##_req[sizeof(struct acomp_req) + \
+                            MAX_SYNC_COMP_REQSIZE] CRYPTO_MINALIGN_ATTR; \
+        struct acomp_req *name = acomp_request_on_stack_init( \
+                __##name##_req, (tfm), (gfp), false)
+
 struct acomp_req;
 
 struct acomp_req_chain {
@@ -83,12 +93,14 @@ struct acomp_req {
  * @compress:          Function performs a compress operation
  * @decompress:                Function performs a de-compress operation
  * @reqsize:           Context size for (de)compression requests
+ * @fb:                        Synchronous fallback tfm
  * @base:              Common crypto API algorithm data structure
  */
 struct crypto_acomp {
        int (*compress)(struct acomp_req *req);
        int (*decompress)(struct acomp_req *req);
        unsigned int reqsize;
+       struct crypto_acomp *fb;
        struct crypto_tfm base;
 };
 
@@ -210,24 +222,68 @@ static inline int crypto_has_acomp(const char *alg_name, u32 type, u32 mask)
        return crypto_has_alg(alg_name, type, mask);
 }
 
+static inline const char *crypto_acomp_alg_name(struct crypto_acomp *tfm)
+{
+       return crypto_tfm_alg_name(crypto_acomp_tfm(tfm));
+}
+
+static inline const char *crypto_acomp_driver_name(struct crypto_acomp *tfm)
+{
+       return crypto_tfm_alg_driver_name(crypto_acomp_tfm(tfm));
+}
+
 /**
  * acomp_request_alloc() -- allocates asynchronous (de)compression request
  *
  * @tfm:       ACOMPRESS tfm handle allocated with crypto_alloc_acomp()
+ * @gfp:       gfp to pass to kzalloc (defaults to GFP_KERNEL)
  *
  * Return:     allocated handle in case of success or NULL in case of an error
  */
-static inline struct acomp_req *acomp_request_alloc_noprof(struct crypto_acomp *tfm)
+static inline struct acomp_req *acomp_request_alloc_extra_noprof(
+       struct crypto_acomp *tfm, size_t extra, gfp_t gfp)
 {
        struct acomp_req *req;
+       size_t len;
+
+       len = ALIGN(sizeof(*req) + crypto_acomp_reqsize(tfm), CRYPTO_MINALIGN);
+       if (check_add_overflow(len, extra, &len))
+               return NULL;
 
-       req = kzalloc_noprof(sizeof(*req) + crypto_acomp_reqsize(tfm), GFP_KERNEL);
+       req = kzalloc_noprof(len, gfp);
        if (likely(req))
                acomp_request_set_tfm(req, tfm);
        return req;
 }
+#define acomp_request_alloc_noprof(tfm, ...) \
+       CONCATENATE(acomp_request_alloc_noprof_, COUNT_ARGS(__VA_ARGS__))( \
+               tfm, ##__VA_ARGS__)
+#define acomp_request_alloc_noprof_0(tfm) \
+       acomp_request_alloc_noprof_1(tfm, GFP_KERNEL)
+#define acomp_request_alloc_noprof_1(tfm, gfp) \
+       acomp_request_alloc_extra_noprof(tfm, 0, gfp)
 #define acomp_request_alloc(...)       alloc_hooks(acomp_request_alloc_noprof(__VA_ARGS__))
 
+/**
+ * acomp_request_alloc_extra() -- allocate acomp request with extra memory
+ *
+ * @tfm:       ACOMPRESS tfm handle allocated with crypto_alloc_acomp()
+ * @extra:     amount of extra memory
+ * @gfp:       gfp to pass to kzalloc
+ *
+ * Return:     allocated handle in case of success or NULL in case of an error
+ */
+#define acomp_request_alloc_extra(...) alloc_hooks(acomp_request_alloc_extra_noprof(__VA_ARGS__))
+
+static inline void *acomp_request_extra(struct acomp_req *req)
+{
+       struct crypto_acomp *tfm = crypto_acomp_reqtfm(req);
+       size_t len;
+
+       len = ALIGN(sizeof(*req) + crypto_acomp_reqsize(tfm), CRYPTO_MINALIGN);
+       return (void *)((char *)req + len);
+}
+
 /**
  * acomp_request_free() -- zeroize and free asynchronous (de)compression
  *                        request as well as the output buffer if allocated
@@ -237,6 +293,8 @@ static inline struct acomp_req *acomp_request_alloc_noprof(struct crypto_acomp *
  */
 static inline void acomp_request_free(struct acomp_req *req)
 {
+       if (!req || (req->base.flags & CRYPTO_TFM_REQ_ON_STACK))
+               return;
        kfree_sensitive(req);
 }
 
@@ -257,7 +315,8 @@ static inline void acomp_request_set_callback(struct acomp_req *req,
                                              void *data)
 {
        u32 keep = CRYPTO_ACOMP_REQ_SRC_VIRT | CRYPTO_ACOMP_REQ_SRC_NONDMA |
-                  CRYPTO_ACOMP_REQ_DST_VIRT | CRYPTO_ACOMP_REQ_DST_NONDMA;
+                  CRYPTO_ACOMP_REQ_DST_VIRT | CRYPTO_ACOMP_REQ_DST_NONDMA |
+                  CRYPTO_TFM_REQ_ON_STACK;
 
        req->base.complete = cmpl;
        req->base.data = data;
@@ -446,4 +505,19 @@ int crypto_acomp_compress(struct acomp_req *req);
  */
 int crypto_acomp_decompress(struct acomp_req *req);
 
+static inline struct acomp_req *acomp_request_on_stack_init(
+       char *buf, struct crypto_acomp *tfm, gfp_t gfp, bool stackonly)
+{
+       struct acomp_req *req;
+
+       if (!stackonly && (req = acomp_request_alloc(tfm, gfp)))
+               return req;
+
+       req = (void *)buf;
+       acomp_request_set_tfm(req, tfm->fb);
+       req->base.flags = CRYPTO_TFM_REQ_ON_STACK;
+
+       return req;
+}
+
 #endif
index 575dbcbc0df46fbe7f3072039e1dd3cc199dca97..c1ed55a0e3bfb3ab89a3ee51811b732f3e0490c4 100644 (file)
 #include <crypto/acompress.h>
 #include <crypto/algapi.h>
 
+#define ACOMP_REQUEST_ON_STACK(name, tfm) \
+        char __##name##_req[sizeof(struct acomp_req) + \
+                            MAX_SYNC_COMP_REQSIZE] CRYPTO_MINALIGN_ATTR; \
+        struct acomp_req *name = acomp_request_on_stack_init( \
+                __##name##_req, (tfm), 0, true)
+
 /**
  * struct acomp_alg - asynchronous compression algorithm
  *
index 61ac11226638beece3d82ea41064295abf8628e7..ea3b95bdbde35e4ad5d66c903c176c0c70c725da 100644 (file)
 #define CRYPTO_TFM_REQ_FORBID_WEAK_KEYS        0x00000100
 #define CRYPTO_TFM_REQ_MAY_SLEEP       0x00000200
 #define CRYPTO_TFM_REQ_MAY_BACKLOG     0x00000400
+#define CRYPTO_TFM_REQ_ON_STACK                0x00000800
 
 /*
  * Miscellaneous stuff.