crypto: acomp - Add ACOMP_REQUEST_CLONE
authorHerbert Xu <herbert@gondor.apana.org.au>
Mon, 7 Apr 2025 10:03:00 +0000 (18:03 +0800)
committerHerbert Xu <herbert@gondor.apana.org.au>
Wed, 16 Apr 2025 07:16:20 +0000 (15:16 +0800)
Add a new helper ACOMP_REQUEST_CLONE that will transform a stack
request into a dynamically allocated one if possible, and otherwise
switch it over to the sycnrhonous fallback transform.  The intended
usage is:

ACOMP_STACK_ON_REQUEST(req, tfm);

...
err = crypto_acomp_compress(req);
/* The request cannot complete synchronously. */
if (err == -EAGAIN) {
/* This will not fail. */
req = ACOMP_REQUEST_CLONE(req, gfp);

/* Redo operation. */
err = crypto_acomp_compress(req);
}

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

index f343b1a4b1d1b37efcfff9d745d3fc9c2df0109c..530b9bfd03a51090fe10b83c66cb9ca44c991b3d 100644 (file)
@@ -316,6 +316,8 @@ int crypto_acomp_compress(struct acomp_req *req)
 {
        struct crypto_acomp *tfm = crypto_acomp_reqtfm(req);
 
+       if (acomp_req_on_stack(req) && acomp_is_async(tfm))
+               return -EAGAIN;
        if (crypto_acomp_req_chain(tfm) || acomp_request_issg(req))
                crypto_acomp_reqtfm(req)->compress(req);
        return acomp_do_req_chain(req, true);
@@ -326,6 +328,8 @@ int crypto_acomp_decompress(struct acomp_req *req)
 {
        struct crypto_acomp *tfm = crypto_acomp_reqtfm(req);
 
+       if (acomp_req_on_stack(req) && acomp_is_async(tfm))
+               return -EAGAIN;
        if (crypto_acomp_req_chain(tfm) || acomp_request_issg(req))
                crypto_acomp_reqtfm(req)->decompress(req);
        return acomp_do_req_chain(req, false);
@@ -603,5 +607,24 @@ int acomp_walk_virt(struct acomp_walk *__restrict walk,
 }
 EXPORT_SYMBOL_GPL(acomp_walk_virt);
 
+struct acomp_req *acomp_request_clone(struct acomp_req *req,
+                                     size_t total, gfp_t gfp)
+{
+       struct crypto_acomp *tfm = crypto_acomp_reqtfm(req);
+       struct acomp_req *nreq;
+
+       nreq = kmalloc(total, gfp);
+       if (!nreq) {
+               acomp_request_set_tfm(req, tfm->fb);
+               req->base.flags = CRYPTO_TFM_REQ_ON_STACK;
+               return req;
+       }
+
+       memcpy(nreq, req, total);
+       acomp_request_set_tfm(req, tfm);
+       return req;
+}
+EXPORT_SYMBOL_GPL(acomp_request_clone);
+
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Asynchronous compression type");
index f383a400885419e1a8ee23012c7171c8c4365a36..93cee67c27c0ba8f9dc32ed0744ea06126149ff3 100644 (file)
 #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_alloc_init( \
+                __##name##_req, (tfm), (gfp))
+
+#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), (gfp), false)
+                __##name##_req, (tfm))
+
+#define ACOMP_REQUEST_CLONE(name, gfp) \
+       acomp_request_clone(name, sizeof(__##name##_req), gfp)
 
 struct acomp_req;
 struct folio;
@@ -571,12 +580,12 @@ 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)
+static inline struct acomp_req *acomp_request_alloc_init(
+       char *buf, struct crypto_acomp *tfm, gfp_t gfp)
 {
        struct acomp_req *req;
 
-       if (!stackonly && (req = acomp_request_alloc(tfm, gfp)))
+       if ((req = acomp_request_alloc(tfm, gfp)))
                return req;
 
        req = (void *)buf;
@@ -586,4 +595,17 @@ static inline struct acomp_req *acomp_request_on_stack_init(
        return req;
 }
 
+static inline struct acomp_req *acomp_request_on_stack_init(
+       char *buf, struct crypto_acomp *tfm)
+{
+       struct acomp_req *req = (void *)buf;
+
+       acomp_request_set_tfm(req, tfm);
+       req->base.flags = CRYPTO_TFM_REQ_ON_STACK;
+       return req;
+}
+
+struct acomp_req *acomp_request_clone(struct acomp_req *req,
+                                     size_t total, gfp_t gfp);
+
 #endif
index 8840fd2c1db5a7b2b3bf9f8d1ba826c1ba023381..b51d66633935a9769ae0b4fbc060584fb310a818 100644 (file)
 #include <linux/spinlock.h>
 #include <linux/workqueue_types.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)
-
 #define ACOMP_FBREQ_ON_STACK(name, req) \
         char __##name##_req[sizeof(struct acomp_req) + \
                             MAX_SYNC_COMP_REQSIZE] CRYPTO_MINALIGN_ATTR; \
@@ -245,9 +239,10 @@ static inline struct acomp_req *acomp_fbreq_on_stack_init(
        char *buf, struct acomp_req *old)
 {
        struct crypto_acomp *tfm = crypto_acomp_reqtfm(old);
-       struct acomp_req *req;
+       struct acomp_req *req = (void *)buf;
 
-       req = acomp_request_on_stack_init(buf, tfm, 0, true);
+       acomp_request_set_tfm(req, tfm->fb);
+       req->base.flags = CRYPTO_TFM_REQ_ON_STACK;
        acomp_request_set_callback(req, acomp_request_flags(old), NULL, NULL);
        req->base.flags &= ~CRYPTO_ACOMP_REQ_PRIVATE;
        req->base.flags |= old->base.flags & CRYPTO_ACOMP_REQ_PRIVATE;