* [v5 PATCH 00/14] crypto: acomp - Add virtual address and folio support
@ 2025-03-15 10:30 Herbert Xu
2025-03-15 10:30 ` [v5 PATCH 01/14] xfrm: ipcomp: Call pskb_may_pull in ipcomp_input Herbert Xu
` (13 more replies)
0 siblings, 14 replies; 24+ messages in thread
From: Herbert Xu @ 2025-03-15 10:30 UTC (permalink / raw)
To: Linux Crypto Mailing List
Cc: Richard Weinberger, Zhihao Cheng, linux-mtd, Rafael J. Wysocki,
Pavel Machek, linux-pm, Steffen Klassert, netdev
v5 removes the incompressible warnings in ubifs, removes more dead
code from qat, and replaces crypto_has_comp with crypto_has_acomp
in hibernate and ipcomp.
This patch series adds virtual address and folio support to acomp.
This finally brings it to feature parity with the legacy crypto_comp,
which enables us to convert the existing users to acomp.
The three users are converted according to their characteristics:
ubifs uses folio+linear, hibernate uses linear only while ipcomp
uses SG only.
Only ipcomp is fully asynchronous, ubifs supports asynchronous
but will wait on it and hibernate is synchronous only.
Herbert Xu (14):
xfrm: ipcomp: Call pskb_may_pull in ipcomp_input
crypto: scomp - Remove support for some non-trivial SG lists
crypto: iaa - Remove dst_null support
crypto: qat - Remove dst_null support
crypto: acomp - Remove dst_free
crypto: scomp - Add chaining and virtual address support
crypto: acomp - Add ACOMP_REQUEST_ALLOC and acomp_request_alloc_extra
crypto: iaa - Use acomp stack fallback
crypto: acomp - Add async nondma fallback
crypto: acomp - Add support for folios
xfrm: ipcomp: Use crypto_acomp interface
PM: hibernate: Use crypto_acomp interface
ubifs: Use crypto_acomp interface
ubifs: Pass folios to acomp
crypto/acompress.c | 148 ++++--
crypto/scompress.c | 189 ++++---
drivers/crypto/intel/iaa/iaa_crypto_main.c | 164 +-----
drivers/crypto/intel/qat/qat_common/qat_bl.c | 159 ------
drivers/crypto/intel/qat/qat_common/qat_bl.h | 6 -
.../intel/qat/qat_common/qat_comp_algs.c | 85 +---
.../intel/qat/qat_common/qat_comp_req.h | 10 -
fs/ubifs/compress.c | 208 ++++++--
fs/ubifs/file.c | 74 +--
fs/ubifs/journal.c | 11 +-
fs/ubifs/ubifs.h | 26 +-
include/crypto/acompress.h | 184 ++++++-
include/crypto/internal/acompress.h | 26 +-
include/crypto/internal/scompress.h | 2 -
include/linux/crypto.h | 1 +
include/net/ipcomp.h | 13 +-
kernel/power/hibernate.c | 5 +-
kernel/power/swap.c | 58 ++-
net/xfrm/xfrm_algo.c | 7 +-
net/xfrm/xfrm_ipcomp.c | 478 +++++++++---------
20 files changed, 932 insertions(+), 922 deletions(-)
--
2.39.5
^ permalink raw reply [flat|nested] 24+ messages in thread
* [v5 PATCH 01/14] xfrm: ipcomp: Call pskb_may_pull in ipcomp_input
2025-03-15 10:30 [v5 PATCH 00/14] crypto: acomp - Add virtual address and folio support Herbert Xu
@ 2025-03-15 10:30 ` Herbert Xu
2025-03-15 10:30 ` [v5 PATCH 02/14] crypto: scomp - Remove support for some non-trivial SG lists Herbert Xu
` (12 subsequent siblings)
13 siblings, 0 replies; 24+ messages in thread
From: Herbert Xu @ 2025-03-15 10:30 UTC (permalink / raw)
To: Linux Crypto Mailing List
Cc: Richard Weinberger, Zhihao Cheng, linux-mtd, Rafael J. Wysocki,
Pavel Machek, linux-pm, Steffen Klassert, netdev
If a malformed packet is received there may not be enough data
to pull. This isn't a problem in practice because the caller
has already done xfrm_parse_spi which in effect does the same
thing.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Acked-by: Steffen Klassert <steffen.klassert@secunet.com>
---
net/xfrm/xfrm_ipcomp.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/net/xfrm/xfrm_ipcomp.c b/net/xfrm/xfrm_ipcomp.c
index 9c0fa0e1786a..43eae94e4b0e 100644
--- a/net/xfrm/xfrm_ipcomp.c
+++ b/net/xfrm/xfrm_ipcomp.c
@@ -97,6 +97,9 @@ int ipcomp_input(struct xfrm_state *x, struct sk_buff *skb)
int err = -ENOMEM;
struct ip_comp_hdr *ipch;
+ if (!pskb_may_pull(skb, sizeof(*ipch)))
+ return -EINVAL;
+
if (skb_linearize_cow(skb))
goto out;
--
2.39.5
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [v5 PATCH 02/14] crypto: scomp - Remove support for some non-trivial SG lists
2025-03-15 10:30 [v5 PATCH 00/14] crypto: acomp - Add virtual address and folio support Herbert Xu
2025-03-15 10:30 ` [v5 PATCH 01/14] xfrm: ipcomp: Call pskb_may_pull in ipcomp_input Herbert Xu
@ 2025-03-15 10:30 ` Herbert Xu
2025-03-15 10:30 ` [v5 PATCH 03/14] crypto: iaa - Remove dst_null support Herbert Xu
` (11 subsequent siblings)
13 siblings, 0 replies; 24+ messages in thread
From: Herbert Xu @ 2025-03-15 10:30 UTC (permalink / raw)
To: Linux Crypto Mailing List
Cc: Richard Weinberger, Zhihao Cheng, linux-mtd, Rafael J. Wysocki,
Pavel Machek, linux-pm, Steffen Klassert, netdev
As the only user of acomp/scomp uses a trivial single-page SG
list, remove support for everything else in preprataion for the
addition of virtual address support.
However, keep support for non-trivial source SG lists as that
user is currently jumping through hoops in order to linearise
the source data.
Limit the source SG linearisation buffer to a single page as
that user never goes over that. The only other potential user
is also unlikely to exceed that (IPComp) and it can easily do
its own linearisation if necessary.
Also keep the destination SG linearisation for IPComp.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
crypto/acompress.c | 1 -
crypto/scompress.c | 127 ++++++++++++++++------------
include/crypto/acompress.h | 17 +---
include/crypto/internal/scompress.h | 2 -
4 files changed, 76 insertions(+), 71 deletions(-)
diff --git a/crypto/acompress.c b/crypto/acompress.c
index 45444e99a9db..194a4b36f97f 100644
--- a/crypto/acompress.c
+++ b/crypto/acompress.c
@@ -73,7 +73,6 @@ static int crypto_acomp_init_tfm(struct crypto_tfm *tfm)
acomp->compress = alg->compress;
acomp->decompress = alg->decompress;
- acomp->dst_free = alg->dst_free;
acomp->reqsize = alg->reqsize;
if (alg->exit)
diff --git a/crypto/scompress.c b/crypto/scompress.c
index a2ce481a10bb..4441c40f541f 100644
--- a/crypto/scompress.c
+++ b/crypto/scompress.c
@@ -12,8 +12,10 @@
#include <crypto/scatterwalk.h>
#include <linux/cryptouser.h>
#include <linux/err.h>
+#include <linux/highmem.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/overflow.h>
#include <linux/scatterlist.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
@@ -23,9 +25,14 @@
#include "compress.h"
+#define SCOMP_SCRATCH_SIZE 65400
+
struct scomp_scratch {
spinlock_t lock;
- void *src;
+ union {
+ void *src;
+ unsigned long saddr;
+ };
void *dst;
};
@@ -66,7 +73,7 @@ static void crypto_scomp_free_scratches(void)
for_each_possible_cpu(i) {
scratch = per_cpu_ptr(&scomp_scratch, i);
- vfree(scratch->src);
+ free_page(scratch->saddr);
vfree(scratch->dst);
scratch->src = NULL;
scratch->dst = NULL;
@@ -79,14 +86,15 @@ static int crypto_scomp_alloc_scratches(void)
int i;
for_each_possible_cpu(i) {
+ struct page *page;
void *mem;
scratch = per_cpu_ptr(&scomp_scratch, i);
- mem = vmalloc_node(SCOMP_SCRATCH_SIZE, cpu_to_node(i));
- if (!mem)
+ page = alloc_pages_node(cpu_to_node(i), GFP_KERNEL, 0);
+ if (!page)
goto error;
- scratch->src = mem;
+ scratch->src = page_address(page);
mem = vmalloc_node(SCOMP_SCRATCH_SIZE, cpu_to_node(i));
if (!mem)
goto error;
@@ -161,76 +169,88 @@ static int crypto_scomp_init_tfm(struct crypto_tfm *tfm)
static int scomp_acomp_comp_decomp(struct acomp_req *req, int dir)
{
+ struct scomp_scratch *scratch = raw_cpu_ptr(&scomp_scratch);
struct crypto_acomp *tfm = crypto_acomp_reqtfm(req);
- void **tfm_ctx = acomp_tfm_ctx(tfm);
+ struct crypto_scomp **tfm_ctx = acomp_tfm_ctx(tfm);
struct crypto_scomp *scomp = *tfm_ctx;
struct crypto_acomp_stream *stream;
- struct scomp_scratch *scratch;
+ unsigned int slen = req->slen;
+ unsigned int dlen = req->dlen;
+ struct page *spage, *dpage;
+ unsigned int soff, doff;
void *src, *dst;
- unsigned int dlen;
+ unsigned int n;
int ret;
- if (!req->src || !req->slen || req->slen > SCOMP_SCRATCH_SIZE)
+ if (!req->src || !slen)
return -EINVAL;
- if (req->dst && !req->dlen)
+ if (!req->dst || !dlen)
return -EINVAL;
- if (!req->dlen || req->dlen > SCOMP_SCRATCH_SIZE)
- req->dlen = SCOMP_SCRATCH_SIZE;
+ soff = req->src->offset;
+ spage = nth_page(sg_page(req->src), soff / PAGE_SIZE);
+ soff = offset_in_page(soff);
- dlen = req->dlen;
-
- scratch = raw_cpu_ptr(&scomp_scratch);
- spin_lock_bh(&scratch->lock);
-
- if (sg_nents(req->src) == 1 && !PageHighMem(sg_page(req->src))) {
- src = page_to_virt(sg_page(req->src)) + req->src->offset;
- } else {
- scatterwalk_map_and_copy(scratch->src, req->src, 0,
- req->slen, 0);
+ n = slen / PAGE_SIZE;
+ n += (offset_in_page(slen) + soff - 1) / PAGE_SIZE;
+ if (slen <= req->src->length && (!PageHighMem(nth_page(spage, n)) ||
+ size_add(soff, slen) <= PAGE_SIZE))
+ src = kmap_local_page(spage) + soff;
+ else
src = scratch->src;
+
+ doff = req->dst->offset;
+ dpage = nth_page(sg_page(req->dst), doff / PAGE_SIZE);
+ doff = offset_in_page(doff);
+
+ n = dlen / PAGE_SIZE;
+ n += (offset_in_page(dlen) + doff - 1) / PAGE_SIZE;
+ if (dlen <= req->dst->length && (!PageHighMem(nth_page(dpage, n)) ||
+ size_add(doff, dlen) <= PAGE_SIZE))
+ dst = kmap_local_page(dpage) + doff;
+ else {
+ if (dlen > SCOMP_SCRATCH_SIZE)
+ dlen = SCOMP_SCRATCH_SIZE;
+ dst = scratch->dst;
}
- if (req->dst && sg_nents(req->dst) == 1 && !PageHighMem(sg_page(req->dst)))
- dst = page_to_virt(sg_page(req->dst)) + req->dst->offset;
- else
- dst = scratch->dst;
+ spin_lock_bh(&scratch->lock);
+
+ if (src == scratch->src)
+ memcpy_from_sglist(src, req->src, 0, slen);
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, stream->ctx);
+ ret = crypto_scomp_compress(scomp, src, slen,
+ dst, &dlen, stream->ctx);
else
- ret = crypto_scomp_decompress(scomp, src, req->slen,
- dst, &req->dlen, stream->ctx);
- spin_unlock(&stream->lock);
- if (!ret) {
- if (!req->dst) {
- req->dst = sgl_alloc(req->dlen, GFP_ATOMIC, NULL);
- if (!req->dst) {
- ret = -ENOMEM;
- goto out;
- }
- } else if (req->dlen > dlen) {
- ret = -ENOSPC;
- goto out;
- }
- if (dst == scratch->dst) {
- scatterwalk_map_and_copy(scratch->dst, req->dst, 0,
- req->dlen, 1);
- } else {
- int nr_pages = DIV_ROUND_UP(req->dst->offset + req->dlen, PAGE_SIZE);
- int i;
- struct page *dst_page = sg_page(req->dst);
+ ret = crypto_scomp_decompress(scomp, src, slen,
+ dst, &dlen, stream->ctx);
- for (i = 0; i < nr_pages; i++)
- flush_dcache_page(dst_page + i);
+ if (dst == scratch->dst)
+ memcpy_to_sglist(req->dst, 0, dst, dlen);
+
+ spin_unlock(&stream->lock);
+ spin_unlock_bh(&scratch->lock);
+
+ req->dlen = dlen;
+
+ if (dst != scratch->dst) {
+ kunmap_local(dst);
+ dlen += doff;
+ for (;;) {
+ flush_dcache_page(dpage);
+ if (dlen <= PAGE_SIZE)
+ break;
+ dlen -= PAGE_SIZE;
+ dpage = nth_page(dpage, 1);
}
}
-out:
- spin_unlock_bh(&scratch->lock);
+ if (src != scratch->src)
+ kunmap_local(src);
+
return ret;
}
@@ -277,7 +297,6 @@ 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;
return 0;
}
diff --git a/include/crypto/acompress.h b/include/crypto/acompress.h
index c4d8a29274c6..53c9e632862b 100644
--- a/include/crypto/acompress.h
+++ b/include/crypto/acompress.h
@@ -18,8 +18,6 @@
#include <linux/spinlock_types.h>
#include <linux/types.h>
-#define CRYPTO_ACOMP_ALLOC_OUTPUT 0x00000001
-
/* Set this bit if source is virtual address instead of SG list. */
#define CRYPTO_ACOMP_REQ_SRC_VIRT 0x00000002
@@ -84,15 +82,12 @@ struct acomp_req {
*
* @compress: Function performs a compress operation
* @decompress: Function performs a de-compress operation
- * @dst_free: Frees destination buffer if allocated inside the
- * algorithm
* @reqsize: Context size for (de)compression requests
* @base: Common crypto API algorithm data structure
*/
struct crypto_acomp {
int (*compress)(struct acomp_req *req);
int (*decompress)(struct acomp_req *req);
- void (*dst_free)(struct scatterlist *dst);
unsigned int reqsize;
struct crypto_tfm base;
};
@@ -261,9 +256,8 @@ static inline void acomp_request_set_callback(struct acomp_req *req,
crypto_completion_t cmpl,
void *data)
{
- u32 keep = CRYPTO_ACOMP_ALLOC_OUTPUT | CRYPTO_ACOMP_REQ_SRC_VIRT |
- CRYPTO_ACOMP_REQ_SRC_NONDMA | CRYPTO_ACOMP_REQ_DST_VIRT |
- CRYPTO_ACOMP_REQ_DST_NONDMA;
+ u32 keep = CRYPTO_ACOMP_REQ_SRC_VIRT | CRYPTO_ACOMP_REQ_SRC_NONDMA |
+ CRYPTO_ACOMP_REQ_DST_VIRT | CRYPTO_ACOMP_REQ_DST_NONDMA;
req->base.complete = cmpl;
req->base.data = data;
@@ -297,13 +291,10 @@ static inline void acomp_request_set_params(struct acomp_req *req,
req->slen = slen;
req->dlen = dlen;
- req->base.flags &= ~(CRYPTO_ACOMP_ALLOC_OUTPUT |
- CRYPTO_ACOMP_REQ_SRC_VIRT |
+ req->base.flags &= ~(CRYPTO_ACOMP_REQ_SRC_VIRT |
CRYPTO_ACOMP_REQ_SRC_NONDMA |
CRYPTO_ACOMP_REQ_DST_VIRT |
CRYPTO_ACOMP_REQ_DST_NONDMA);
- if (!req->dst)
- req->base.flags |= CRYPTO_ACOMP_ALLOC_OUTPUT;
}
/**
@@ -403,7 +394,6 @@ static inline void acomp_request_set_dst_dma(struct acomp_req *req,
req->dvirt = dst;
req->dlen = dlen;
- req->base.flags &= ~CRYPTO_ACOMP_ALLOC_OUTPUT;
req->base.flags &= ~CRYPTO_ACOMP_REQ_DST_NONDMA;
req->base.flags |= CRYPTO_ACOMP_REQ_DST_VIRT;
}
@@ -424,7 +414,6 @@ static inline void acomp_request_set_dst_nondma(struct acomp_req *req,
req->dvirt = dst;
req->dlen = dlen;
- req->base.flags &= ~CRYPTO_ACOMP_ALLOC_OUTPUT;
req->base.flags |= CRYPTO_ACOMP_REQ_DST_NONDMA;
req->base.flags |= CRYPTO_ACOMP_REQ_DST_VIRT;
}
diff --git a/include/crypto/internal/scompress.h b/include/crypto/internal/scompress.h
index 88986ab8ce15..f25aa2ea3b48 100644
--- a/include/crypto/internal/scompress.h
+++ b/include/crypto/internal/scompress.h
@@ -12,8 +12,6 @@
#include <crypto/acompress.h>
#include <crypto/algapi.h>
-#define SCOMP_SCRATCH_SIZE 131072
-
struct acomp_req;
struct crypto_scomp {
--
2.39.5
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [v5 PATCH 03/14] crypto: iaa - Remove dst_null support
2025-03-15 10:30 [v5 PATCH 00/14] crypto: acomp - Add virtual address and folio support Herbert Xu
2025-03-15 10:30 ` [v5 PATCH 01/14] xfrm: ipcomp: Call pskb_may_pull in ipcomp_input Herbert Xu
2025-03-15 10:30 ` [v5 PATCH 02/14] crypto: scomp - Remove support for some non-trivial SG lists Herbert Xu
@ 2025-03-15 10:30 ` Herbert Xu
2025-03-15 10:30 ` [v5 PATCH 04/14] crypto: qat " Herbert Xu
` (10 subsequent siblings)
13 siblings, 0 replies; 24+ messages in thread
From: Herbert Xu @ 2025-03-15 10:30 UTC (permalink / raw)
To: Linux Crypto Mailing List
Cc: Richard Weinberger, Zhihao Cheng, linux-mtd, Rafael J. Wysocki,
Pavel Machek, linux-pm, Steffen Klassert, netdev
Remove the unused dst_null support.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
drivers/crypto/intel/iaa/iaa_crypto_main.c | 136 +--------------------
1 file changed, 6 insertions(+), 130 deletions(-)
diff --git a/drivers/crypto/intel/iaa/iaa_crypto_main.c b/drivers/crypto/intel/iaa/iaa_crypto_main.c
index 990ea46955bb..50cb100bf1c8 100644
--- a/drivers/crypto/intel/iaa/iaa_crypto_main.c
+++ b/drivers/crypto/intel/iaa/iaa_crypto_main.c
@@ -1136,8 +1136,7 @@ static int iaa_compress(struct crypto_tfm *tfm, struct acomp_req *req,
struct idxd_wq *wq,
dma_addr_t src_addr, unsigned int slen,
dma_addr_t dst_addr, unsigned int *dlen,
- u32 *compression_crc,
- bool disable_async)
+ u32 *compression_crc)
{
struct iaa_device_compression_mode *active_compression_mode;
struct iaa_compression_ctx *ctx = crypto_tfm_ctx(tfm);
@@ -1180,7 +1179,7 @@ static int iaa_compress(struct crypto_tfm *tfm, struct acomp_req *req,
desc->src2_size = sizeof(struct aecs_comp_table_record);
desc->completion_addr = idxd_desc->compl_dma;
- if (ctx->use_irq && !disable_async) {
+ if (ctx->use_irq) {
desc->flags |= IDXD_OP_FLAG_RCI;
idxd_desc->crypto.req = req;
@@ -1193,7 +1192,7 @@ static int iaa_compress(struct crypto_tfm *tfm, struct acomp_req *req,
" src_addr %llx, dst_addr %llx\n", __func__,
active_compression_mode->name,
src_addr, dst_addr);
- } else if (ctx->async_mode && !disable_async)
+ } else if (ctx->async_mode)
req->base.data = idxd_desc;
dev_dbg(dev, "%s: compression mode %s,"
@@ -1214,7 +1213,7 @@ static int iaa_compress(struct crypto_tfm *tfm, struct acomp_req *req,
update_total_comp_calls();
update_wq_comp_calls(wq);
- if (ctx->async_mode && !disable_async) {
+ if (ctx->async_mode) {
ret = -EINPROGRESS;
dev_dbg(dev, "%s: returning -EINPROGRESS\n", __func__);
goto out;
@@ -1234,7 +1233,7 @@ static int iaa_compress(struct crypto_tfm *tfm, struct acomp_req *req,
*compression_crc = idxd_desc->iax_completion->crc;
- if (!ctx->async_mode || disable_async)
+ if (!ctx->async_mode)
idxd_free_desc(wq, idxd_desc);
out:
return ret;
@@ -1500,13 +1499,11 @@ static int iaa_comp_acompress(struct acomp_req *req)
struct iaa_compression_ctx *compression_ctx;
struct crypto_tfm *tfm = req->base.tfm;
dma_addr_t src_addr, dst_addr;
- bool disable_async = false;
int nr_sgs, cpu, ret = 0;
struct iaa_wq *iaa_wq;
u32 compression_crc;
struct idxd_wq *wq;
struct device *dev;
- int order = -1;
compression_ctx = crypto_tfm_ctx(tfm);
@@ -1536,21 +1533,6 @@ static int iaa_comp_acompress(struct acomp_req *req)
iaa_wq = idxd_wq_get_private(wq);
- if (!req->dst) {
- gfp_t flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : GFP_ATOMIC;
-
- /* incompressible data will always be < 2 * slen */
- req->dlen = 2 * req->slen;
- order = order_base_2(round_up(req->dlen, PAGE_SIZE) / PAGE_SIZE);
- req->dst = sgl_alloc_order(req->dlen, order, false, flags, NULL);
- if (!req->dst) {
- ret = -ENOMEM;
- order = -1;
- goto out;
- }
- disable_async = true;
- }
-
dev = &wq->idxd->pdev->dev;
nr_sgs = dma_map_sg(dev, req->src, sg_nents(req->src), DMA_TO_DEVICE);
@@ -1580,7 +1562,7 @@ static int iaa_comp_acompress(struct acomp_req *req)
req->dst, req->dlen, sg_dma_len(req->dst));
ret = iaa_compress(tfm, req, wq, src_addr, req->slen, dst_addr,
- &req->dlen, &compression_crc, disable_async);
+ &req->dlen, &compression_crc);
if (ret == -EINPROGRESS)
return ret;
@@ -1611,100 +1593,6 @@ static int iaa_comp_acompress(struct acomp_req *req)
out:
iaa_wq_put(wq);
- if (order >= 0)
- sgl_free_order(req->dst, order);
-
- return ret;
-}
-
-static int iaa_comp_adecompress_alloc_dest(struct acomp_req *req)
-{
- gfp_t flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ?
- GFP_KERNEL : GFP_ATOMIC;
- struct crypto_tfm *tfm = req->base.tfm;
- dma_addr_t src_addr, dst_addr;
- int nr_sgs, cpu, ret = 0;
- struct iaa_wq *iaa_wq;
- struct device *dev;
- struct idxd_wq *wq;
- int order = -1;
-
- cpu = get_cpu();
- wq = wq_table_next_wq(cpu);
- put_cpu();
- if (!wq) {
- pr_debug("no wq configured for cpu=%d\n", cpu);
- return -ENODEV;
- }
-
- ret = iaa_wq_get(wq);
- if (ret) {
- pr_debug("no wq available for cpu=%d\n", cpu);
- return -ENODEV;
- }
-
- iaa_wq = idxd_wq_get_private(wq);
-
- dev = &wq->idxd->pdev->dev;
-
- nr_sgs = dma_map_sg(dev, req->src, sg_nents(req->src), DMA_TO_DEVICE);
- if (nr_sgs <= 0 || nr_sgs > 1) {
- dev_dbg(dev, "couldn't map src sg for iaa device %d,"
- " wq %d: ret=%d\n", iaa_wq->iaa_device->idxd->id,
- iaa_wq->wq->id, ret);
- ret = -EIO;
- goto out;
- }
- src_addr = sg_dma_address(req->src);
- dev_dbg(dev, "dma_map_sg, src_addr %llx, nr_sgs %d, req->src %p,"
- " req->slen %d, sg_dma_len(sg) %d\n", src_addr, nr_sgs,
- req->src, req->slen, sg_dma_len(req->src));
-
- req->dlen = 4 * req->slen; /* start with ~avg comp rato */
-alloc_dest:
- order = order_base_2(round_up(req->dlen, PAGE_SIZE) / PAGE_SIZE);
- req->dst = sgl_alloc_order(req->dlen, order, false, flags, NULL);
- if (!req->dst) {
- ret = -ENOMEM;
- order = -1;
- goto out;
- }
-
- nr_sgs = dma_map_sg(dev, req->dst, sg_nents(req->dst), DMA_FROM_DEVICE);
- if (nr_sgs <= 0 || nr_sgs > 1) {
- dev_dbg(dev, "couldn't map dst sg for iaa device %d,"
- " wq %d: ret=%d\n", iaa_wq->iaa_device->idxd->id,
- iaa_wq->wq->id, ret);
- ret = -EIO;
- goto err_map_dst;
- }
-
- dst_addr = sg_dma_address(req->dst);
- dev_dbg(dev, "dma_map_sg, dst_addr %llx, nr_sgs %d, req->dst %p,"
- " req->dlen %d, sg_dma_len(sg) %d\n", dst_addr, nr_sgs,
- req->dst, req->dlen, sg_dma_len(req->dst));
- ret = iaa_decompress(tfm, req, wq, src_addr, req->slen,
- dst_addr, &req->dlen, true);
- if (ret == -EOVERFLOW) {
- dma_unmap_sg(dev, req->dst, sg_nents(req->dst), DMA_FROM_DEVICE);
- req->dlen *= 2;
- if (req->dlen > CRYPTO_ACOMP_DST_MAX)
- goto err_map_dst;
- goto alloc_dest;
- }
-
- if (ret != 0)
- dev_dbg(dev, "asynchronous decompress failed ret=%d\n", ret);
-
- dma_unmap_sg(dev, req->dst, sg_nents(req->dst), DMA_FROM_DEVICE);
-err_map_dst:
- dma_unmap_sg(dev, req->src, sg_nents(req->src), DMA_TO_DEVICE);
-out:
- iaa_wq_put(wq);
-
- if (order >= 0)
- sgl_free_order(req->dst, order);
-
return ret;
}
@@ -1727,9 +1615,6 @@ static int iaa_comp_adecompress(struct acomp_req *req)
return -EINVAL;
}
- if (!req->dst)
- return iaa_comp_adecompress_alloc_dest(req);
-
cpu = get_cpu();
wq = wq_table_next_wq(cpu);
put_cpu();
@@ -1810,19 +1695,10 @@ static int iaa_comp_init_fixed(struct crypto_acomp *acomp_tfm)
return 0;
}
-static void dst_free(struct scatterlist *sgl)
-{
- /*
- * Called for req->dst = NULL cases but we free elsewhere
- * using sgl_free_order().
- */
-}
-
static struct acomp_alg iaa_acomp_fixed_deflate = {
.init = iaa_comp_init_fixed,
.compress = iaa_comp_acompress,
.decompress = iaa_comp_adecompress,
- .dst_free = dst_free,
.base = {
.cra_name = "deflate",
.cra_driver_name = "deflate-iaa",
--
2.39.5
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [v5 PATCH 04/14] crypto: qat - Remove dst_null support
2025-03-15 10:30 [v5 PATCH 00/14] crypto: acomp - Add virtual address and folio support Herbert Xu
` (2 preceding siblings ...)
2025-03-15 10:30 ` [v5 PATCH 03/14] crypto: iaa - Remove dst_null support Herbert Xu
@ 2025-03-15 10:30 ` Herbert Xu
2025-03-15 10:30 ` [v5 PATCH 05/14] crypto: acomp - Remove dst_free Herbert Xu
` (9 subsequent siblings)
13 siblings, 0 replies; 24+ messages in thread
From: Herbert Xu @ 2025-03-15 10:30 UTC (permalink / raw)
To: Linux Crypto Mailing List
Cc: Richard Weinberger, Zhihao Cheng, linux-mtd, Rafael J. Wysocki,
Pavel Machek, linux-pm, Steffen Klassert, netdev
Remove the unused dst_null support.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
drivers/crypto/intel/qat/qat_common/qat_bl.c | 159 ------------------
drivers/crypto/intel/qat/qat_common/qat_bl.h | 6 -
.../intel/qat/qat_common/qat_comp_algs.c | 85 +---------
.../intel/qat/qat_common/qat_comp_req.h | 10 --
4 files changed, 1 insertion(+), 259 deletions(-)
diff --git a/drivers/crypto/intel/qat/qat_common/qat_bl.c b/drivers/crypto/intel/qat/qat_common/qat_bl.c
index 338acf29c487..5e4dad4693ca 100644
--- a/drivers/crypto/intel/qat/qat_common/qat_bl.c
+++ b/drivers/crypto/intel/qat/qat_common/qat_bl.c
@@ -251,162 +251,3 @@ int qat_bl_sgl_to_bufl(struct adf_accel_dev *accel_dev,
extra_dst_buff, sz_extra_dst_buff,
sskip, dskip, flags);
}
-
-static void qat_bl_sgl_unmap(struct adf_accel_dev *accel_dev,
- struct qat_alg_buf_list *bl)
-{
- struct device *dev = &GET_DEV(accel_dev);
- int n = bl->num_bufs;
- int i;
-
- for (i = 0; i < n; i++)
- if (!dma_mapping_error(dev, bl->buffers[i].addr))
- dma_unmap_single(dev, bl->buffers[i].addr,
- bl->buffers[i].len, DMA_FROM_DEVICE);
-}
-
-static int qat_bl_sgl_map(struct adf_accel_dev *accel_dev,
- struct scatterlist *sgl,
- struct qat_alg_buf_list **bl)
-{
- struct device *dev = &GET_DEV(accel_dev);
- struct qat_alg_buf_list *bufl;
- int node = dev_to_node(dev);
- struct scatterlist *sg;
- int n, i, sg_nctr;
- size_t sz;
-
- n = sg_nents(sgl);
- sz = struct_size(bufl, buffers, n);
- bufl = kzalloc_node(sz, GFP_KERNEL, node);
- if (unlikely(!bufl))
- return -ENOMEM;
-
- for (i = 0; i < n; i++)
- bufl->buffers[i].addr = DMA_MAPPING_ERROR;
-
- sg_nctr = 0;
- for_each_sg(sgl, sg, n, i) {
- int y = sg_nctr;
-
- if (!sg->length)
- continue;
-
- bufl->buffers[y].addr = dma_map_single(dev, sg_virt(sg),
- sg->length,
- DMA_FROM_DEVICE);
- bufl->buffers[y].len = sg->length;
- if (unlikely(dma_mapping_error(dev, bufl->buffers[y].addr)))
- goto err_map;
- sg_nctr++;
- }
- bufl->num_bufs = sg_nctr;
- bufl->num_mapped_bufs = sg_nctr;
-
- *bl = bufl;
-
- return 0;
-
-err_map:
- for (i = 0; i < n; i++)
- if (!dma_mapping_error(dev, bufl->buffers[i].addr))
- dma_unmap_single(dev, bufl->buffers[i].addr,
- bufl->buffers[i].len,
- DMA_FROM_DEVICE);
- kfree(bufl);
- *bl = NULL;
-
- return -ENOMEM;
-}
-
-static void qat_bl_sgl_free_unmap(struct adf_accel_dev *accel_dev,
- struct scatterlist *sgl,
- struct qat_alg_buf_list *bl,
- bool free_bl)
-{
- if (bl) {
- qat_bl_sgl_unmap(accel_dev, bl);
-
- if (free_bl)
- kfree(bl);
- }
- if (sgl)
- sgl_free(sgl);
-}
-
-static int qat_bl_sgl_alloc_map(struct adf_accel_dev *accel_dev,
- struct scatterlist **sgl,
- struct qat_alg_buf_list **bl,
- unsigned int dlen,
- gfp_t gfp)
-{
- struct scatterlist *dst;
- int ret;
-
- dst = sgl_alloc(dlen, gfp, NULL);
- if (!dst) {
- dev_err(&GET_DEV(accel_dev), "sg_alloc failed\n");
- return -ENOMEM;
- }
-
- ret = qat_bl_sgl_map(accel_dev, dst, bl);
- if (ret)
- goto err;
-
- *sgl = dst;
-
- return 0;
-
-err:
- sgl_free(dst);
- *sgl = NULL;
- return ret;
-}
-
-int qat_bl_realloc_map_new_dst(struct adf_accel_dev *accel_dev,
- struct scatterlist **sg,
- unsigned int dlen,
- struct qat_request_buffs *qat_bufs,
- gfp_t gfp)
-{
- struct device *dev = &GET_DEV(accel_dev);
- dma_addr_t new_blp = DMA_MAPPING_ERROR;
- struct qat_alg_buf_list *new_bl;
- struct scatterlist *new_sg;
- size_t new_bl_size;
- int ret;
-
- ret = qat_bl_sgl_alloc_map(accel_dev, &new_sg, &new_bl, dlen, gfp);
- if (ret)
- return ret;
-
- new_bl_size = struct_size(new_bl, buffers, new_bl->num_bufs);
-
- /* Map new firmware SGL descriptor */
- new_blp = dma_map_single(dev, new_bl, new_bl_size, DMA_TO_DEVICE);
- if (unlikely(dma_mapping_error(dev, new_blp)))
- goto err;
-
- /* Unmap old firmware SGL descriptor */
- dma_unmap_single(dev, qat_bufs->bloutp, qat_bufs->sz_out, DMA_TO_DEVICE);
-
- /* Free and unmap old scatterlist */
- qat_bl_sgl_free_unmap(accel_dev, *sg, qat_bufs->blout,
- !qat_bufs->sgl_dst_valid);
-
- qat_bufs->sgl_dst_valid = false;
- qat_bufs->blout = new_bl;
- qat_bufs->bloutp = new_blp;
- qat_bufs->sz_out = new_bl_size;
-
- *sg = new_sg;
-
- return 0;
-err:
- qat_bl_sgl_free_unmap(accel_dev, new_sg, new_bl, true);
-
- if (!dma_mapping_error(dev, new_blp))
- dma_unmap_single(dev, new_blp, new_bl_size, DMA_TO_DEVICE);
-
- return -ENOMEM;
-}
diff --git a/drivers/crypto/intel/qat/qat_common/qat_bl.h b/drivers/crypto/intel/qat/qat_common/qat_bl.h
index 3f5b79015400..2827d5055d3c 100644
--- a/drivers/crypto/intel/qat/qat_common/qat_bl.h
+++ b/drivers/crypto/intel/qat/qat_common/qat_bl.h
@@ -65,10 +65,4 @@ static inline gfp_t qat_algs_alloc_flags(struct crypto_async_request *req)
return req->flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : GFP_ATOMIC;
}
-int qat_bl_realloc_map_new_dst(struct adf_accel_dev *accel_dev,
- struct scatterlist **newd,
- unsigned int dlen,
- struct qat_request_buffs *qat_bufs,
- gfp_t gfp);
-
#endif
diff --git a/drivers/crypto/intel/qat/qat_common/qat_comp_algs.c b/drivers/crypto/intel/qat/qat_common/qat_comp_algs.c
index 2ba4aa22e092..a6e02405d402 100644
--- a/drivers/crypto/intel/qat/qat_common/qat_comp_algs.c
+++ b/drivers/crypto/intel/qat/qat_common/qat_comp_algs.c
@@ -29,11 +29,6 @@ struct qat_compression_ctx {
int (*qat_comp_callback)(struct qat_compression_req *qat_req, void *resp);
};
-struct qat_dst {
- bool is_null;
- int resubmitted;
-};
-
struct qat_compression_req {
u8 req[QAT_COMP_REQ_SIZE];
struct qat_compression_ctx *qat_compression_ctx;
@@ -42,8 +37,6 @@ struct qat_compression_req {
enum direction dir;
int actual_dlen;
struct qat_alg_req alg_req;
- struct work_struct resubmit;
- struct qat_dst dst;
};
static int qat_alg_send_dc_message(struct qat_compression_req *qat_req,
@@ -60,46 +53,6 @@ static int qat_alg_send_dc_message(struct qat_compression_req *qat_req,
return qat_alg_send_message(alg_req);
}
-static void qat_comp_resubmit(struct work_struct *work)
-{
- struct qat_compression_req *qat_req =
- container_of(work, struct qat_compression_req, resubmit);
- struct qat_compression_ctx *ctx = qat_req->qat_compression_ctx;
- struct adf_accel_dev *accel_dev = ctx->inst->accel_dev;
- struct qat_request_buffs *qat_bufs = &qat_req->buf;
- struct qat_compression_instance *inst = ctx->inst;
- struct acomp_req *areq = qat_req->acompress_req;
- struct crypto_acomp *tfm = crypto_acomp_reqtfm(areq);
- unsigned int dlen = CRYPTO_ACOMP_DST_MAX;
- u8 *req = qat_req->req;
- dma_addr_t dfbuf;
- int ret;
-
- areq->dlen = dlen;
-
- dev_dbg(&GET_DEV(accel_dev), "[%s][%s] retry NULL dst request - dlen = %d\n",
- crypto_tfm_alg_driver_name(crypto_acomp_tfm(tfm)),
- qat_req->dir == COMPRESSION ? "comp" : "decomp", dlen);
-
- ret = qat_bl_realloc_map_new_dst(accel_dev, &areq->dst, dlen, qat_bufs,
- qat_algs_alloc_flags(&areq->base));
- if (ret)
- goto err;
-
- qat_req->dst.resubmitted = true;
-
- dfbuf = qat_req->buf.bloutp;
- qat_comp_override_dst(req, dfbuf, dlen);
-
- ret = qat_alg_send_dc_message(qat_req, inst, &areq->base);
- if (ret != -ENOSPC)
- return;
-
-err:
- qat_bl_free_bufl(accel_dev, qat_bufs);
- acomp_request_complete(areq, ret);
-}
-
static void qat_comp_generic_callback(struct qat_compression_req *qat_req,
void *resp)
{
@@ -131,21 +84,6 @@ static void qat_comp_generic_callback(struct qat_compression_req *qat_req,
areq->dlen = 0;
- if (qat_req->dir == DECOMPRESSION && qat_req->dst.is_null) {
- if (cmp_err == ERR_CODE_OVERFLOW_ERROR) {
- if (qat_req->dst.resubmitted) {
- dev_dbg(&GET_DEV(accel_dev),
- "Output does not fit destination buffer\n");
- res = -EOVERFLOW;
- goto end;
- }
-
- INIT_WORK(&qat_req->resubmit, qat_comp_resubmit);
- adf_misc_wq_queue_work(&qat_req->resubmit);
- return;
- }
- }
-
if (unlikely(status != ICP_QAT_FW_COMN_STATUS_FLAG_OK))
goto end;
@@ -245,29 +183,9 @@ static int qat_comp_alg_compress_decompress(struct acomp_req *areq, enum directi
if (!areq->src || !slen)
return -EINVAL;
- if (areq->dst && !dlen)
+ if (!areq->dst || !dlen)
return -EINVAL;
- qat_req->dst.is_null = false;
-
- /* Handle acomp requests that require the allocation of a destination
- * buffer. The size of the destination buffer is double the source
- * buffer (rounded up to the size of a page) to fit the decompressed
- * output or an expansion on the data for compression.
- */
- if (!areq->dst) {
- qat_req->dst.is_null = true;
-
- dlen = round_up(2 * slen, PAGE_SIZE);
- areq->dst = sgl_alloc(dlen, f, NULL);
- if (!areq->dst)
- return -ENOMEM;
-
- dlen -= dhdr + dftr;
- areq->dlen = dlen;
- qat_req->dst.resubmitted = false;
- }
-
if (dir == COMPRESSION) {
params.extra_dst_buff = inst->dc_data->ovf_buff_p;
ovf_buff_sz = inst->dc_data->ovf_buff_sz;
@@ -329,7 +247,6 @@ static struct acomp_alg qat_acomp[] = { {
.exit = qat_comp_alg_exit_tfm,
.compress = qat_comp_alg_compress,
.decompress = qat_comp_alg_decompress,
- .dst_free = sgl_free,
.reqsize = sizeof(struct qat_compression_req),
}};
diff --git a/drivers/crypto/intel/qat/qat_common/qat_comp_req.h b/drivers/crypto/intel/qat/qat_common/qat_comp_req.h
index 404e32c5e778..18a1f33a6db9 100644
--- a/drivers/crypto/intel/qat/qat_common/qat_comp_req.h
+++ b/drivers/crypto/intel/qat/qat_common/qat_comp_req.h
@@ -25,16 +25,6 @@ static inline void qat_comp_create_req(void *ctx, void *req, u64 src, u32 slen,
req_pars->out_buffer_sz = dlen;
}
-static inline void qat_comp_override_dst(void *req, u64 dst, u32 dlen)
-{
- struct icp_qat_fw_comp_req *fw_req = req;
- struct icp_qat_fw_comp_req_params *req_pars = &fw_req->comp_pars;
-
- fw_req->comn_mid.dest_data_addr = dst;
- fw_req->comn_mid.dst_length = dlen;
- req_pars->out_buffer_sz = dlen;
-}
-
static inline void qat_comp_create_compression_req(void *ctx, void *req,
u64 src, u32 slen,
u64 dst, u32 dlen,
--
2.39.5
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [v5 PATCH 05/14] crypto: acomp - Remove dst_free
2025-03-15 10:30 [v5 PATCH 00/14] crypto: acomp - Add virtual address and folio support Herbert Xu
` (3 preceding siblings ...)
2025-03-15 10:30 ` [v5 PATCH 04/14] crypto: qat " Herbert Xu
@ 2025-03-15 10:30 ` Herbert Xu
2025-03-15 10:30 ` [v5 PATCH 06/14] crypto: scomp - Add chaining and virtual address support Herbert Xu
` (8 subsequent siblings)
13 siblings, 0 replies; 24+ messages in thread
From: Herbert Xu @ 2025-03-15 10:30 UTC (permalink / raw)
To: Linux Crypto Mailing List
Cc: Richard Weinberger, Zhihao Cheng, linux-mtd, Rafael J. Wysocki,
Pavel Machek, linux-pm, Steffen Klassert, netdev
Remove the unused dst_free hook.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
include/crypto/internal/acompress.h | 2 --
1 file changed, 2 deletions(-)
diff --git a/include/crypto/internal/acompress.h b/include/crypto/internal/acompress.h
index 957a5ed7c7f1..575dbcbc0df4 100644
--- a/include/crypto/internal/acompress.h
+++ b/include/crypto/internal/acompress.h
@@ -17,7 +17,6 @@
*
* @compress: Function performs a compress operation
* @decompress: Function performs a de-compress operation
- * @dst_free: Frees destination buffer if allocated inside the algorithm
* @init: Initialize the cryptographic transformation object.
* This function is used to initialize the cryptographic
* transformation object. This function is called only once at
@@ -38,7 +37,6 @@
struct acomp_alg {
int (*compress)(struct acomp_req *req);
int (*decompress)(struct acomp_req *req);
- void (*dst_free)(struct scatterlist *dst);
int (*init)(struct crypto_acomp *tfm);
void (*exit)(struct crypto_acomp *tfm);
--
2.39.5
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [v5 PATCH 06/14] crypto: scomp - Add chaining and virtual address support
2025-03-15 10:30 [v5 PATCH 00/14] crypto: acomp - Add virtual address and folio support Herbert Xu
` (4 preceding siblings ...)
2025-03-15 10:30 ` [v5 PATCH 05/14] crypto: acomp - Remove dst_free Herbert Xu
@ 2025-03-15 10:30 ` Herbert Xu
2025-03-15 10:30 ` [v5 PATCH 07/14] crypto: acomp - Add ACOMP_REQUEST_ALLOC and acomp_request_alloc_extra Herbert Xu
` (7 subsequent siblings)
13 siblings, 0 replies; 24+ messages in thread
From: Herbert Xu @ 2025-03-15 10:30 UTC (permalink / raw)
To: Linux Crypto Mailing List
Cc: Richard Weinberger, Zhihao Cheng, linux-mtd, Rafael J. Wysocki,
Pavel Machek, linux-pm, Steffen Klassert, netdev
Add chaining and virtual address support to all scomp algorithms.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
crypto/scompress.c | 96 +++++++++++++++++++++++++++++++---------------
1 file changed, 65 insertions(+), 31 deletions(-)
diff --git a/crypto/scompress.c b/crypto/scompress.c
index 4441c40f541f..ba9b22ba53fe 100644
--- a/crypto/scompress.c
+++ b/crypto/scompress.c
@@ -178,8 +178,9 @@ static int scomp_acomp_comp_decomp(struct acomp_req *req, int dir)
unsigned int dlen = req->dlen;
struct page *spage, *dpage;
unsigned int soff, doff;
- void *src, *dst;
unsigned int n;
+ const u8 *src;
+ u8 *dst;
int ret;
if (!req->src || !slen)
@@ -188,37 +189,47 @@ static int scomp_acomp_comp_decomp(struct acomp_req *req, int dir)
if (!req->dst || !dlen)
return -EINVAL;
- soff = req->src->offset;
- spage = nth_page(sg_page(req->src), soff / PAGE_SIZE);
- soff = offset_in_page(soff);
-
- n = slen / PAGE_SIZE;
- n += (offset_in_page(slen) + soff - 1) / PAGE_SIZE;
- if (slen <= req->src->length && (!PageHighMem(nth_page(spage, n)) ||
- size_add(soff, slen) <= PAGE_SIZE))
- src = kmap_local_page(spage) + soff;
- else
- src = scratch->src;
-
- doff = req->dst->offset;
- dpage = nth_page(sg_page(req->dst), doff / PAGE_SIZE);
- doff = offset_in_page(doff);
-
- n = dlen / PAGE_SIZE;
- n += (offset_in_page(dlen) + doff - 1) / PAGE_SIZE;
- if (dlen <= req->dst->length && (!PageHighMem(nth_page(dpage, n)) ||
- size_add(doff, dlen) <= PAGE_SIZE))
- dst = kmap_local_page(dpage) + doff;
+ if (acomp_request_src_isvirt(req))
+ src = req->svirt;
else {
- if (dlen > SCOMP_SCRATCH_SIZE)
- dlen = SCOMP_SCRATCH_SIZE;
- dst = scratch->dst;
+ soff = req->src->offset;
+ spage = nth_page(sg_page(req->src), soff / PAGE_SIZE);
+ soff = offset_in_page(soff);
+
+ n = slen / PAGE_SIZE;
+ n += (offset_in_page(slen) + soff - 1) / PAGE_SIZE;
+ if (slen <= req->src->length &&
+ (!PageHighMem(nth_page(spage, n)) ||
+ size_add(soff, slen) <= PAGE_SIZE))
+ src = kmap_local_page(spage) + soff;
+ else
+ src = scratch->src;
+ }
+
+ if (acomp_request_dst_isvirt(req))
+ dst = req->dvirt;
+ else {
+ doff = req->dst->offset;
+ dpage = nth_page(sg_page(req->dst), doff / PAGE_SIZE);
+ doff = offset_in_page(doff);
+
+ n = dlen / PAGE_SIZE;
+ n += (offset_in_page(dlen) + doff - 1) / PAGE_SIZE;
+ if (dlen <= req->dst->length &&
+ (!PageHighMem(nth_page(dpage, n)) ||
+ size_add(doff, dlen) <= PAGE_SIZE))
+ dst = kmap_local_page(dpage) + doff;
+ else {
+ if (dlen > SCOMP_SCRATCH_SIZE)
+ dlen = SCOMP_SCRATCH_SIZE;
+ dst = scratch->dst;
+ }
}
spin_lock_bh(&scratch->lock);
if (src == scratch->src)
- memcpy_from_sglist(src, req->src, 0, slen);
+ memcpy_from_sglist(scratch->src, req->src, 0, slen);
stream = raw_cpu_ptr(crypto_scomp_alg(scomp)->stream);
spin_lock(&stream->lock);
@@ -237,7 +248,7 @@ static int scomp_acomp_comp_decomp(struct acomp_req *req, int dir)
req->dlen = dlen;
- if (dst != scratch->dst) {
+ if (!acomp_request_dst_isvirt(req) && dst != scratch->dst) {
kunmap_local(dst);
dlen += doff;
for (;;) {
@@ -248,20 +259,34 @@ static int scomp_acomp_comp_decomp(struct acomp_req *req, int dir)
dpage = nth_page(dpage, 1);
}
}
- if (src != scratch->src)
+ if (!acomp_request_src_isvirt(req) && src != scratch->src)
kunmap_local(src);
return ret;
}
+static int scomp_acomp_chain(struct acomp_req *req, int dir)
+{
+ struct acomp_req *r2;
+ int err;
+
+ err = scomp_acomp_comp_decomp(req, dir);
+ req->base.err = err;
+
+ list_for_each_entry(r2, &req->base.list, base.list)
+ r2->base.err = scomp_acomp_comp_decomp(r2, dir);
+
+ return err;
+}
+
static int scomp_acomp_compress(struct acomp_req *req)
{
- return scomp_acomp_comp_decomp(req, 1);
+ return scomp_acomp_chain(req, 1);
}
static int scomp_acomp_decompress(struct acomp_req *req)
{
- return scomp_acomp_comp_decomp(req, 0);
+ return scomp_acomp_chain(req, 0);
}
static void crypto_exit_scomp_ops_async(struct crypto_tfm *tfm)
@@ -322,12 +347,21 @@ static const struct crypto_type crypto_scomp_type = {
.tfmsize = offsetof(struct crypto_scomp, base),
};
-int crypto_register_scomp(struct scomp_alg *alg)
+static void scomp_prepare_alg(struct scomp_alg *alg)
{
struct crypto_alg *base = &alg->calg.base;
comp_prepare_alg(&alg->calg);
+ base->cra_flags |= CRYPTO_ALG_REQ_CHAIN;
+}
+
+int crypto_register_scomp(struct scomp_alg *alg)
+{
+ struct crypto_alg *base = &alg->calg.base;
+
+ scomp_prepare_alg(alg);
+
base->cra_type = &crypto_scomp_type;
base->cra_flags |= CRYPTO_ALG_TYPE_SCOMPRESS;
--
2.39.5
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [v5 PATCH 07/14] crypto: acomp - Add ACOMP_REQUEST_ALLOC and acomp_request_alloc_extra
2025-03-15 10:30 [v5 PATCH 00/14] crypto: acomp - Add virtual address and folio support Herbert Xu
` (5 preceding siblings ...)
2025-03-15 10:30 ` [v5 PATCH 06/14] crypto: scomp - Add chaining and virtual address support Herbert Xu
@ 2025-03-15 10:30 ` Herbert Xu
2025-03-15 10:30 ` [v5 PATCH 08/14] crypto: iaa - Use acomp stack fallback Herbert Xu
` (6 subsequent siblings)
13 siblings, 0 replies; 24+ messages in thread
From: Herbert Xu @ 2025-03-15 10:30 UTC (permalink / raw)
To: Linux Crypto Mailing List
Cc: Richard Weinberger, Zhihao Cheng, linux-mtd, Rafael J. Wysocki,
Pavel Machek, linux-pm, Steffen Klassert, netdev
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 | 38 ++++++++++++--
include/crypto/acompress.h | 80 +++++++++++++++++++++++++++--
include/crypto/internal/acompress.h | 6 +++
include/linux/crypto.h | 1 +
4 files changed, 117 insertions(+), 8 deletions(-)
diff --git a/crypto/acompress.c b/crypto/acompress.c
index 194a4b36f97f..9da033ded193 100644
--- a/crypto/acompress.c
+++ b/crypto/acompress.c
@@ -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)
diff --git a/include/crypto/acompress.h b/include/crypto/acompress.h
index 53c9e632862b..03cb381c2c54 100644
--- a/include/crypto/acompress.h
+++ b/include/crypto/acompress.h
@@ -10,9 +10,11 @@
#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>
@@ -32,6 +34,14 @@
#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;
- req = kzalloc_noprof(sizeof(*req) + crypto_acomp_reqsize(tfm), GFP_KERNEL);
+ len = ALIGN(sizeof(*req) + crypto_acomp_reqsize(tfm), CRYPTO_MINALIGN);
+ if (check_add_overflow(len, extra, &len))
+ return NULL;
+
+ 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
diff --git a/include/crypto/internal/acompress.h b/include/crypto/internal/acompress.h
index 575dbcbc0df4..c1ed55a0e3bf 100644
--- a/include/crypto/internal/acompress.h
+++ b/include/crypto/internal/acompress.h
@@ -12,6 +12,12 @@
#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
*
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index 61ac11226638..ea3b95bdbde3 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -138,6 +138,7 @@
#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.
--
2.39.5
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [v5 PATCH 08/14] crypto: iaa - Use acomp stack fallback
2025-03-15 10:30 [v5 PATCH 00/14] crypto: acomp - Add virtual address and folio support Herbert Xu
` (6 preceding siblings ...)
2025-03-15 10:30 ` [v5 PATCH 07/14] crypto: acomp - Add ACOMP_REQUEST_ALLOC and acomp_request_alloc_extra Herbert Xu
@ 2025-03-15 10:30 ` Herbert Xu
2025-03-15 10:30 ` [v5 PATCH 09/14] crypto: acomp - Add async nondma fallback Herbert Xu
` (5 subsequent siblings)
13 siblings, 0 replies; 24+ messages in thread
From: Herbert Xu @ 2025-03-15 10:30 UTC (permalink / raw)
To: Linux Crypto Mailing List
Cc: Richard Weinberger, Zhihao Cheng, linux-mtd, Rafael J. Wysocki,
Pavel Machek, linux-pm, Steffen Klassert, netdev
Use ACOMP_REQUEST_ON_STACK instead of allocating legacy fallback
compression transform.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
drivers/crypto/intel/iaa/iaa_crypto_main.c | 28 +++++-----------------
1 file changed, 6 insertions(+), 22 deletions(-)
diff --git a/drivers/crypto/intel/iaa/iaa_crypto_main.c b/drivers/crypto/intel/iaa/iaa_crypto_main.c
index 50cb100bf1c8..09d9589f2d68 100644
--- a/drivers/crypto/intel/iaa/iaa_crypto_main.c
+++ b/drivers/crypto/intel/iaa/iaa_crypto_main.c
@@ -33,8 +33,6 @@ static unsigned int nr_cpus_per_node;
/* Number of physical cpus sharing each iaa instance */
static unsigned int cpus_per_iaa;
-static struct crypto_comp *deflate_generic_tfm;
-
/* Per-cpu lookup table for balanced wqs */
static struct wq_table_entry __percpu *wq_table;
@@ -1001,17 +999,14 @@ static inline int check_completion(struct device *dev,
static int deflate_generic_decompress(struct acomp_req *req)
{
- void *src, *dst;
+ ACOMP_REQUEST_ON_STACK(fbreq, crypto_acomp_reqtfm(req));
int ret;
- src = kmap_local_page(sg_page(req->src)) + req->src->offset;
- dst = kmap_local_page(sg_page(req->dst)) + req->dst->offset;
-
- ret = crypto_comp_decompress(deflate_generic_tfm,
- src, req->slen, dst, &req->dlen);
-
- kunmap_local(src);
- kunmap_local(dst);
+ acomp_request_set_callback(fbreq, 0, NULL, NULL);
+ acomp_request_set_params(fbreq, req->src, req->dst, req->slen,
+ req->dlen);
+ ret = crypto_acomp_decompress(fbreq);
+ req->dlen = fbreq->dlen;
update_total_sw_decomp_calls();
@@ -1898,15 +1893,6 @@ static int __init iaa_crypto_init_module(void)
}
nr_cpus_per_node = nr_cpus / nr_nodes;
- if (crypto_has_comp("deflate-generic", 0, 0))
- deflate_generic_tfm = crypto_alloc_comp("deflate-generic", 0, 0);
-
- if (IS_ERR_OR_NULL(deflate_generic_tfm)) {
- pr_err("IAA could not alloc %s tfm: errcode = %ld\n",
- "deflate-generic", PTR_ERR(deflate_generic_tfm));
- return -ENOMEM;
- }
-
ret = iaa_aecs_init_fixed();
if (ret < 0) {
pr_debug("IAA fixed compression mode init failed\n");
@@ -1948,7 +1934,6 @@ static int __init iaa_crypto_init_module(void)
err_driver_reg:
iaa_aecs_cleanup_fixed();
err_aecs_init:
- crypto_free_comp(deflate_generic_tfm);
goto out;
}
@@ -1965,7 +1950,6 @@ static void __exit iaa_crypto_cleanup_module(void)
&driver_attr_verify_compress);
idxd_driver_unregister(&iaa_crypto_driver);
iaa_aecs_cleanup_fixed();
- crypto_free_comp(deflate_generic_tfm);
pr_debug("cleaned up\n");
}
--
2.39.5
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [v5 PATCH 09/14] crypto: acomp - Add async nondma fallback
2025-03-15 10:30 [v5 PATCH 00/14] crypto: acomp - Add virtual address and folio support Herbert Xu
` (7 preceding siblings ...)
2025-03-15 10:30 ` [v5 PATCH 08/14] crypto: iaa - Use acomp stack fallback Herbert Xu
@ 2025-03-15 10:30 ` Herbert Xu
2025-03-15 10:30 ` [v5 PATCH 10/14] crypto: acomp - Add support for folios Herbert Xu
` (4 subsequent siblings)
13 siblings, 0 replies; 24+ messages in thread
From: Herbert Xu @ 2025-03-15 10:30 UTC (permalink / raw)
To: Linux Crypto Mailing List
Cc: Richard Weinberger, Zhihao Cheng, linux-mtd, Rafael J. Wysocki,
Pavel Machek, linux-pm, Steffen Klassert, netdev
Add support for passing non-DMA virtual addresses to async drivers
by passing them along to the fallback software algorithm.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
crypto/acompress.c | 69 +++++++++++++++++++++++++++-------------------
1 file changed, 41 insertions(+), 28 deletions(-)
diff --git a/crypto/acompress.c b/crypto/acompress.c
index 9da033ded193..d54abc27330f 100644
--- a/crypto/acompress.c
+++ b/crypto/acompress.c
@@ -152,20 +152,6 @@ struct crypto_acomp *crypto_alloc_acomp_node(const char *alg_name, u32 type,
}
EXPORT_SYMBOL_GPL(crypto_alloc_acomp_node);
-static bool acomp_request_has_nondma(struct acomp_req *req)
-{
- struct acomp_req *r2;
-
- if (acomp_request_isnondma(req))
- return true;
-
- list_for_each_entry(r2, &req->base.list, base.list)
- if (acomp_request_isnondma(r2))
- return true;
-
- return false;
-}
-
static void acomp_save_req(struct acomp_req *req, crypto_completion_t cplt)
{
struct crypto_acomp *tfm = crypto_acomp_reqtfm(req);
@@ -234,6 +220,45 @@ static void acomp_virt_to_sg(struct acomp_req *req)
}
}
+static int acomp_do_nondma(struct acomp_req_chain *state,
+ struct acomp_req *req)
+{
+ u32 keep = CRYPTO_ACOMP_REQ_SRC_VIRT |
+ CRYPTO_ACOMP_REQ_SRC_NONDMA |
+ CRYPTO_ACOMP_REQ_DST_VIRT |
+ CRYPTO_ACOMP_REQ_DST_NONDMA;
+ ACOMP_REQUEST_ON_STACK(fbreq, crypto_acomp_reqtfm(req));
+ int err;
+
+ acomp_request_set_callback(fbreq, req->base.flags, NULL, NULL);
+ fbreq->base.flags &= ~keep;
+ fbreq->base.flags |= req->base.flags & keep;
+ fbreq->src = req->src;
+ fbreq->dst = req->dst;
+ fbreq->slen = req->slen;
+ fbreq->dlen = req->dlen;
+
+ if (state->op == crypto_acomp_reqtfm(req)->compress)
+ err = crypto_acomp_compress(fbreq);
+ else
+ err = crypto_acomp_decompress(fbreq);
+
+ req->dlen = fbreq->dlen;
+ return err;
+}
+
+static int acomp_do_one_req(struct acomp_req_chain *state,
+ struct acomp_req *req)
+{
+ state->cur = req;
+
+ if (acomp_request_isnondma(req))
+ return acomp_do_nondma(state, req);
+
+ acomp_virt_to_sg(req);
+ return state->op(req);
+}
+
static int acomp_reqchain_finish(struct acomp_req_chain *state,
int err, u32 mask)
{
@@ -252,10 +277,8 @@ static int acomp_reqchain_finish(struct acomp_req_chain *state,
req->base.flags &= mask;
req->base.complete = acomp_reqchain_done;
req->base.data = state;
- state->cur = req;
- acomp_virt_to_sg(req);
- err = state->op(req);
+ err = acomp_do_one_req(state, req);
if (err == -EINPROGRESS) {
if (!list_empty(&state->head))
@@ -308,27 +331,17 @@ static int acomp_do_req_chain(struct acomp_req *req,
(!acomp_request_chained(req) && !acomp_request_isvirt(req)))
return op(req);
- /*
- * There are no in-kernel users that do this. If and ever
- * such users come into being then we could add a fall-back
- * path.
- */
- if (acomp_request_has_nondma(req))
- return -EINVAL;
-
if (acomp_is_async(tfm)) {
acomp_save_req(req, acomp_reqchain_done);
state = req->base.data;
}
state->op = op;
- state->cur = req;
state->src = NULL;
INIT_LIST_HEAD(&state->head);
list_splice_init(&req->base.list, &state->head);
- acomp_virt_to_sg(req);
- err = op(req);
+ err = acomp_do_one_req(state, req);
if (err == -EBUSY || err == -EINPROGRESS)
return -EBUSY;
--
2.39.5
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [v5 PATCH 10/14] crypto: acomp - Add support for folios
2025-03-15 10:30 [v5 PATCH 00/14] crypto: acomp - Add virtual address and folio support Herbert Xu
` (8 preceding siblings ...)
2025-03-15 10:30 ` [v5 PATCH 09/14] crypto: acomp - Add async nondma fallback Herbert Xu
@ 2025-03-15 10:30 ` Herbert Xu
2025-03-19 9:57 ` Herbert Xu
2025-03-15 10:30 ` [v5 PATCH 11/14] xfrm: ipcomp: Use crypto_acomp interface Herbert Xu
` (3 subsequent siblings)
13 siblings, 1 reply; 24+ messages in thread
From: Herbert Xu @ 2025-03-15 10:30 UTC (permalink / raw)
To: Linux Crypto Mailing List
Cc: Richard Weinberger, Zhihao Cheng, linux-mtd, Rafael J. Wysocki,
Pavel Machek, linux-pm, Steffen Klassert, netdev
For many users, it's easier to supply a folio rather than an SG
list since they already have them. Add support for folios to the
acomp interface.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
crypto/acompress.c | 40 +++++++++++--
crypto/scompress.c | 68 ++++++++++++++--------
include/crypto/acompress.h | 89 +++++++++++++++++++++++++++--
include/crypto/internal/acompress.h | 18 ++++++
4 files changed, 182 insertions(+), 33 deletions(-)
diff --git a/crypto/acompress.c b/crypto/acompress.c
index d54abc27330f..6ef335f5bf27 100644
--- a/crypto/acompress.c
+++ b/crypto/acompress.c
@@ -12,6 +12,7 @@
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/page-flags.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/string.h>
@@ -189,18 +190,25 @@ static void acomp_reqchain_virt(struct acomp_req_chain *state, int err)
req->base.err = err;
state = &req->chain;
- if (state->src)
+ if (state->flags & CRYPTO_ACOMP_REQ_SRC_VIRT)
acomp_request_set_src_dma(req, state->src, slen);
- if (state->dst)
+ else if (state->flags & CRYPTO_ACOMP_REQ_SRC_FOLIO)
+ acomp_request_set_src_folio(req, state->sfolio, state->soff, slen);
+ if (state->flags & CRYPTO_ACOMP_REQ_DST_VIRT)
acomp_request_set_dst_dma(req, state->dst, dlen);
- state->src = NULL;
- state->dst = NULL;
+ else if (state->flags & CRYPTO_ACOMP_REQ_DST_FOLIO)
+ acomp_request_set_dst_folio(req, state->dfolio, state->doff, dlen);
}
static void acomp_virt_to_sg(struct acomp_req *req)
{
struct acomp_req_chain *state = &req->chain;
+ state->flags = req->base.flags & (CRYPTO_ACOMP_REQ_SRC_VIRT |
+ CRYPTO_ACOMP_REQ_DST_VIRT |
+ CRYPTO_ACOMP_REQ_SRC_FOLIO |
+ CRYPTO_ACOMP_REQ_DST_FOLIO);
+
if (acomp_request_src_isvirt(req)) {
unsigned int slen = req->slen;
const u8 *svirt = req->svirt;
@@ -208,6 +216,17 @@ static void acomp_virt_to_sg(struct acomp_req *req)
state->src = svirt;
sg_init_one(&state->ssg, svirt, slen);
acomp_request_set_src_sg(req, &state->ssg, slen);
+ } else if (acomp_request_src_isfolio(req)) {
+ struct folio *folio = req->sfolio;
+ unsigned int slen = req->slen;
+ size_t off = req->soff;
+
+ state->sfolio = folio;
+ state->soff = off;
+ sg_init_table(&state->ssg, 1);
+ sg_set_page(&state->ssg, folio_page(folio, off / PAGE_SIZE),
+ slen, off % PAGE_SIZE);
+ acomp_request_set_src_sg(req, &state->ssg, slen);
}
if (acomp_request_dst_isvirt(req)) {
@@ -217,6 +236,17 @@ static void acomp_virt_to_sg(struct acomp_req *req)
state->dst = dvirt;
sg_init_one(&state->dsg, dvirt, dlen);
acomp_request_set_dst_sg(req, &state->dsg, dlen);
+ } else if (acomp_request_dst_isfolio(req)) {
+ struct folio *folio = req->dfolio;
+ unsigned int dlen = req->dlen;
+ size_t off = req->doff;
+
+ state->dfolio = folio;
+ state->doff = off;
+ sg_init_table(&state->dsg, 1);
+ sg_set_page(&state->dsg, folio_page(folio, off / PAGE_SIZE),
+ dlen, off % PAGE_SIZE);
+ acomp_request_set_src_sg(req, &state->dsg, dlen);
}
}
@@ -328,7 +358,7 @@ static int acomp_do_req_chain(struct acomp_req *req,
int err;
if (crypto_acomp_req_chain(tfm) ||
- (!acomp_request_chained(req) && !acomp_request_isvirt(req)))
+ (!acomp_request_chained(req) && acomp_request_issg(req)))
return op(req);
if (acomp_is_async(tfm)) {
diff --git a/crypto/scompress.c b/crypto/scompress.c
index ba9b22ba53fe..dc239ea8a46c 100644
--- a/crypto/scompress.c
+++ b/crypto/scompress.c
@@ -177,9 +177,10 @@ static int scomp_acomp_comp_decomp(struct acomp_req *req, int dir)
unsigned int slen = req->slen;
unsigned int dlen = req->dlen;
struct page *spage, *dpage;
- unsigned int soff, doff;
unsigned int n;
const u8 *src;
+ size_t soff;
+ size_t doff;
u8 *dst;
int ret;
@@ -192,38 +193,57 @@ static int scomp_acomp_comp_decomp(struct acomp_req *req, int dir)
if (acomp_request_src_isvirt(req))
src = req->svirt;
else {
- soff = req->src->offset;
- spage = nth_page(sg_page(req->src), soff / PAGE_SIZE);
- soff = offset_in_page(soff);
+ src = scratch->src;
+ do {
+ if (acomp_request_src_isfolio(req)) {
+ spage = folio_page(req->sfolio, 0);
+ soff = req->soff;
+ } else if (slen <= req->src->length) {
+ spage = sg_page(req->src);
+ soff = req->src->offset;
+ } else
+ break;
- n = slen / PAGE_SIZE;
- n += (offset_in_page(slen) + soff - 1) / PAGE_SIZE;
- if (slen <= req->src->length &&
- (!PageHighMem(nth_page(spage, n)) ||
- size_add(soff, slen) <= PAGE_SIZE))
+ spage = nth_page(spage, soff / PAGE_SIZE);
+ soff = offset_in_page(soff);
+
+ n = slen / PAGE_SIZE;
+ n += (offset_in_page(slen) + soff - 1) / PAGE_SIZE;
+ if (PageHighMem(nth_page(spage, n)) &&
+ size_add(soff, slen) <= PAGE_SIZE)
+ break;
src = kmap_local_page(spage) + soff;
- else
- src = scratch->src;
+ } while (0);
}
if (acomp_request_dst_isvirt(req))
dst = req->dvirt;
else {
- doff = req->dst->offset;
- dpage = nth_page(sg_page(req->dst), doff / PAGE_SIZE);
- doff = offset_in_page(doff);
+ unsigned int max = SCOMP_SCRATCH_SIZE;
- n = dlen / PAGE_SIZE;
- n += (offset_in_page(dlen) + doff - 1) / PAGE_SIZE;
- if (dlen <= req->dst->length &&
- (!PageHighMem(nth_page(dpage, n)) ||
- size_add(doff, dlen) <= PAGE_SIZE))
+ dst = scratch->dst;
+ do {
+ if (acomp_request_dst_isfolio(req)) {
+ dpage = folio_page(req->dfolio, 0);
+ doff = req->doff;
+ } else if (dlen <= req->dst->length) {
+ dpage = sg_page(req->dst);
+ doff = req->dst->offset;
+ } else
+ break;
+
+ dpage = nth_page(dpage, doff / PAGE_SIZE);
+ doff = offset_in_page(doff);
+
+ n = dlen / PAGE_SIZE;
+ n += (offset_in_page(dlen) + doff - 1) / PAGE_SIZE;
+ if (PageHighMem(dpage + n) &&
+ size_add(doff, dlen) <= PAGE_SIZE)
+ break;
dst = kmap_local_page(dpage) + doff;
- else {
- if (dlen > SCOMP_SCRATCH_SIZE)
- dlen = SCOMP_SCRATCH_SIZE;
- dst = scratch->dst;
- }
+ max = dlen;
+ } while (0);
+ dlen = min(dlen, max);
}
spin_lock_bh(&scratch->lock);
diff --git a/include/crypto/acompress.h b/include/crypto/acompress.h
index 03cb381c2c54..c497c73baf13 100644
--- a/include/crypto/acompress.h
+++ b/include/crypto/acompress.h
@@ -32,6 +32,12 @@
/* Set this bit for if virtual address destination cannot be used for DMA. */
#define CRYPTO_ACOMP_REQ_DST_NONDMA 0x00000010
+/* Set this bit if source is a folio. */
+#define CRYPTO_ACOMP_REQ_SRC_FOLIO 0x00000020
+
+/* Set this bit if destination is a folio. */
+#define CRYPTO_ACOMP_REQ_DST_FOLIO 0x00000040
+
#define CRYPTO_ACOMP_DST_MAX 131072
#define MAX_SYNC_COMP_REQSIZE 0
@@ -43,6 +49,7 @@
__##name##_req, (tfm), (gfp), false)
struct acomp_req;
+struct folio;
struct acomp_req_chain {
struct list_head head;
@@ -53,16 +60,31 @@ struct acomp_req_chain {
void *data;
struct scatterlist ssg;
struct scatterlist dsg;
- const u8 *src;
- u8 *dst;
+ union {
+ const u8 *src;
+ struct folio *sfolio;
+ };
+ union {
+ u8 *dst;
+ struct folio *dfolio;
+ };
+ size_t soff;
+ size_t doff;
+ u32 flags;
};
/**
* struct acomp_req - asynchronous (de)compression request
*
* @base: Common attributes for asynchronous crypto requests
- * @src: Source Data
- * @dst: Destination data
+ * @src: Source scatterlist
+ * @dst: Destination scatterlist
+ * @svirt: Source virtual address
+ * @dvirt: Destination virtual address
+ * @sfolio: Source folio
+ * @soff: Source folio offset
+ * @dfolio: Destination folio
+ * @doff: Destination folio offset
* @slen: Size of the input buffer
* @dlen: Size of the output buffer and number of bytes produced
* @chain: Private API code data, do not use
@@ -73,11 +95,15 @@ struct acomp_req {
union {
struct scatterlist *src;
const u8 *svirt;
+ struct folio *sfolio;
};
union {
struct scatterlist *dst;
u8 *dvirt;
+ struct folio *dfolio;
};
+ size_t soff;
+ size_t doff;
unsigned int slen;
unsigned int dlen;
@@ -316,6 +342,7 @@ static inline void acomp_request_set_callback(struct acomp_req *req,
{
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_SRC_FOLIO | CRYPTO_ACOMP_REQ_DST_FOLIO |
CRYPTO_TFM_REQ_ON_STACK;
req->base.complete = cmpl;
@@ -352,6 +379,8 @@ static inline void acomp_request_set_params(struct acomp_req *req,
req->base.flags &= ~(CRYPTO_ACOMP_REQ_SRC_VIRT |
CRYPTO_ACOMP_REQ_SRC_NONDMA |
+ CRYPTO_ACOMP_REQ_SRC_FOLIO |
+ CRYPTO_ACOMP_REQ_DST_FOLIO |
CRYPTO_ACOMP_REQ_DST_VIRT |
CRYPTO_ACOMP_REQ_DST_NONDMA);
}
@@ -374,6 +403,7 @@ static inline void acomp_request_set_src_sg(struct acomp_req *req,
req->base.flags &= ~CRYPTO_ACOMP_REQ_SRC_NONDMA;
req->base.flags &= ~CRYPTO_ACOMP_REQ_SRC_VIRT;
+ req->base.flags &= ~CRYPTO_ACOMP_REQ_SRC_FOLIO;
}
/**
@@ -393,6 +423,7 @@ static inline void acomp_request_set_src_dma(struct acomp_req *req,
req->slen = slen;
req->base.flags &= ~CRYPTO_ACOMP_REQ_SRC_NONDMA;
+ req->base.flags &= ~CRYPTO_ACOMP_REQ_SRC_FOLIO;
req->base.flags |= CRYPTO_ACOMP_REQ_SRC_VIRT;
}
@@ -413,10 +444,34 @@ static inline void acomp_request_set_src_nondma(struct acomp_req *req,
req->svirt = src;
req->slen = slen;
+ req->base.flags &= ~CRYPTO_ACOMP_REQ_SRC_FOLIO;
req->base.flags |= CRYPTO_ACOMP_REQ_SRC_NONDMA;
req->base.flags |= CRYPTO_ACOMP_REQ_SRC_VIRT;
}
+/**
+ * acomp_request_set_src_folio() -- Sets source folio
+ *
+ * Sets source folio required by an acomp operation.
+ *
+ * @req: asynchronous compress request
+ * @folio: pointer to input folio
+ * @off: input folio offset
+ * @len: size of the input buffer
+ */
+static inline void acomp_request_set_src_folio(struct acomp_req *req,
+ struct folio *folio, size_t off,
+ unsigned int len)
+{
+ req->sfolio = folio;
+ req->soff = off;
+ req->slen = len;
+
+ req->base.flags &= ~CRYPTO_ACOMP_REQ_SRC_NONDMA;
+ req->base.flags &= ~CRYPTO_ACOMP_REQ_SRC_VIRT;
+ req->base.flags |= CRYPTO_ACOMP_REQ_SRC_FOLIO;
+}
+
/**
* acomp_request_set_dst_sg() -- Sets destination scatterlist
*
@@ -435,6 +490,7 @@ static inline void acomp_request_set_dst_sg(struct acomp_req *req,
req->base.flags &= ~CRYPTO_ACOMP_REQ_DST_NONDMA;
req->base.flags &= ~CRYPTO_ACOMP_REQ_DST_VIRT;
+ req->base.flags &= ~CRYPTO_ACOMP_REQ_DST_FOLIO;
}
/**
@@ -454,6 +510,7 @@ static inline void acomp_request_set_dst_dma(struct acomp_req *req,
req->dlen = dlen;
req->base.flags &= ~CRYPTO_ACOMP_REQ_DST_NONDMA;
+ req->base.flags &= ~CRYPTO_ACOMP_REQ_DST_FOLIO;
req->base.flags |= CRYPTO_ACOMP_REQ_DST_VIRT;
}
@@ -473,10 +530,34 @@ static inline void acomp_request_set_dst_nondma(struct acomp_req *req,
req->dvirt = dst;
req->dlen = dlen;
+ req->base.flags &= ~CRYPTO_ACOMP_REQ_DST_FOLIO;
req->base.flags |= CRYPTO_ACOMP_REQ_DST_NONDMA;
req->base.flags |= CRYPTO_ACOMP_REQ_DST_VIRT;
}
+/**
+ * acomp_request_set_dst_folio() -- Sets destination folio
+ *
+ * Sets destination folio required by an acomp operation.
+ *
+ * @req: asynchronous compress request
+ * @folio: pointer to input folio
+ * @off: input folio offset
+ * @len: size of the input buffer
+ */
+static inline void acomp_request_set_dst_folio(struct acomp_req *req,
+ struct folio *folio, size_t off,
+ unsigned int len)
+{
+ req->dfolio = folio;
+ req->doff = off;
+ req->dlen = len;
+
+ req->base.flags &= ~CRYPTO_ACOMP_REQ_DST_NONDMA;
+ req->base.flags &= ~CRYPTO_ACOMP_REQ_DST_VIRT;
+ req->base.flags |= CRYPTO_ACOMP_REQ_DST_FOLIO;
+}
+
static inline void acomp_request_chain(struct acomp_req *req,
struct acomp_req *head)
{
diff --git a/include/crypto/internal/acompress.h b/include/crypto/internal/acompress.h
index c1ed55a0e3bf..aaf59f3236fa 100644
--- a/include/crypto/internal/acompress.h
+++ b/include/crypto/internal/acompress.h
@@ -103,6 +103,14 @@ static inline bool acomp_request_chained(struct acomp_req *req)
return crypto_request_chained(&req->base);
}
+static inline bool acomp_request_issg(struct acomp_req *req)
+{
+ return !(req->base.flags & (CRYPTO_ACOMP_REQ_SRC_VIRT |
+ CRYPTO_ACOMP_REQ_DST_VIRT |
+ CRYPTO_ACOMP_REQ_SRC_FOLIO |
+ CRYPTO_ACOMP_REQ_DST_FOLIO));
+}
+
static inline bool acomp_request_src_isvirt(struct acomp_req *req)
{
return req->base.flags & CRYPTO_ACOMP_REQ_SRC_VIRT;
@@ -135,6 +143,16 @@ static inline bool acomp_request_isnondma(struct acomp_req *req)
CRYPTO_ACOMP_REQ_DST_NONDMA);
}
+static inline bool acomp_request_src_isfolio(struct acomp_req *req)
+{
+ return req->base.flags & CRYPTO_ACOMP_REQ_SRC_FOLIO;
+}
+
+static inline bool acomp_request_dst_isfolio(struct acomp_req *req)
+{
+ return req->base.flags & CRYPTO_ACOMP_REQ_DST_FOLIO;
+}
+
static inline bool crypto_acomp_req_chain(struct crypto_acomp *tfm)
{
return crypto_tfm_req_chain(&tfm->base);
--
2.39.5
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [v5 PATCH 11/14] xfrm: ipcomp: Use crypto_acomp interface
2025-03-15 10:30 [v5 PATCH 00/14] crypto: acomp - Add virtual address and folio support Herbert Xu
` (9 preceding siblings ...)
2025-03-15 10:30 ` [v5 PATCH 10/14] crypto: acomp - Add support for folios Herbert Xu
@ 2025-03-15 10:30 ` Herbert Xu
2025-03-20 9:33 ` Herbert Xu
2025-04-25 12:11 ` Sabrina Dubroca
2025-03-15 10:30 ` [v5 PATCH 12/14] PM: hibernate: " Herbert Xu
` (2 subsequent siblings)
13 siblings, 2 replies; 24+ messages in thread
From: Herbert Xu @ 2025-03-15 10:30 UTC (permalink / raw)
To: Linux Crypto Mailing List
Cc: Richard Weinberger, Zhihao Cheng, linux-mtd, Rafael J. Wysocki,
Pavel Machek, linux-pm, Steffen Klassert, netdev
Replace the legacy comperssion interface with the new acomp
interface. This is the first user to make full user of the
asynchronous nature of acomp by plugging into the existing xfrm
resume interface.
As a result of SG support by acomp, the linear scratch buffer
in ipcomp can be removed.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
include/net/ipcomp.h | 13 +-
net/xfrm/xfrm_algo.c | 7 +-
net/xfrm/xfrm_ipcomp.c | 477 ++++++++++++++++++++---------------------
3 files changed, 236 insertions(+), 261 deletions(-)
diff --git a/include/net/ipcomp.h b/include/net/ipcomp.h
index 8660a2a6d1fc..51401f01e2a5 100644
--- a/include/net/ipcomp.h
+++ b/include/net/ipcomp.h
@@ -3,20 +3,9 @@
#define _NET_IPCOMP_H
#include <linux/skbuff.h>
-#include <linux/types.h>
-
-#define IPCOMP_SCRATCH_SIZE 65400
-
-struct crypto_comp;
-struct ip_comp_hdr;
-
-struct ipcomp_data {
- u16 threshold;
- struct crypto_comp * __percpu *tfms;
-};
struct ip_comp_hdr;
-struct sk_buff;
+struct netlink_ext_ack;
struct xfrm_state;
int ipcomp_input(struct xfrm_state *x, struct sk_buff *skb);
diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c
index e6da7e8495c9..749011e031c0 100644
--- a/net/xfrm/xfrm_algo.c
+++ b/net/xfrm/xfrm_algo.c
@@ -5,13 +5,13 @@
* Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
*/
+#include <crypto/acompress.h>
#include <crypto/aead.h>
#include <crypto/hash.h>
#include <crypto/skcipher.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pfkeyv2.h>
-#include <linux/crypto.h>
#include <linux/scatterlist.h>
#include <net/xfrm.h>
#if IS_ENABLED(CONFIG_INET_ESP) || IS_ENABLED(CONFIG_INET6_ESP)
@@ -669,7 +669,7 @@ static const struct xfrm_algo_list xfrm_ealg_list = {
};
static const struct xfrm_algo_list xfrm_calg_list = {
- .find = crypto_has_comp,
+ .find = crypto_has_acomp,
.algs = calg_list,
.entries = ARRAY_SIZE(calg_list),
};
@@ -828,8 +828,7 @@ 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, 0);
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 43eae94e4b0e..a5246227951f 100644
--- a/net/xfrm/xfrm_ipcomp.c
+++ b/net/xfrm/xfrm_ipcomp.c
@@ -3,7 +3,7 @@
* IP Payload Compression Protocol (IPComp) - RFC3173.
*
* Copyright (c) 2003 James Morris <jmorris@intercode.com.au>
- * Copyright (c) 2003-2008 Herbert Xu <herbert@gondor.apana.org.au>
+ * Copyright (c) 2003-2025 Herbert Xu <herbert@gondor.apana.org.au>
*
* Todo:
* - Tunable compression parameters.
@@ -11,169 +11,240 @@
* - Adaptive compression.
*/
-#include <linux/crypto.h>
+#include <crypto/acompress.h>
#include <linux/err.h>
-#include <linux/list.h>
#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/percpu.h>
+#include <linux/skbuff_ref.h>
#include <linux/slab.h>
-#include <linux/smp.h>
-#include <linux/vmalloc.h>
-#include <net/ip.h>
#include <net/ipcomp.h>
#include <net/xfrm.h>
-struct ipcomp_tfms {
- struct list_head list;
- struct crypto_comp * __percpu *tfms;
- int users;
+#define IPCOMP_SCRATCH_SIZE 65400
+
+struct ipcomp_skb_cb {
+ struct xfrm_skb_cb xfrm;
+ struct acomp_req *req;
};
-static DEFINE_MUTEX(ipcomp_resource_mutex);
-static void * __percpu *ipcomp_scratches;
-static int ipcomp_scratch_users;
-static LIST_HEAD(ipcomp_tfms_list);
+struct ipcomp_data {
+ u16 threshold;
+ struct crypto_acomp *tfm;
+};
-static int ipcomp_decompress(struct xfrm_state *x, struct sk_buff *skb)
+struct ipcomp_req_extra {
+ struct xfrm_state *x;
+ struct scatterlist sg[];
+};
+
+static inline struct ipcomp_skb_cb *ipcomp_cb(struct sk_buff *skb)
{
- struct ipcomp_data *ipcd = x->data;
- const int plen = skb->len;
- 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 ipcomp_skb_cb *cb = (void *)skb->cb;
- if (err)
- return err;
+ BUILD_BUG_ON(sizeof(*cb) > sizeof(skb->cb));
+ return cb;
+}
- if (dlen < (plen + sizeof(struct ip_comp_hdr)))
- return -EINVAL;
+static int ipcomp_post_acomp(struct sk_buff *skb, int err, int hlen)
+{
+ struct acomp_req *req = ipcomp_cb(skb)->req;
+ struct ipcomp_req_extra *extra;
+ const int plen = skb->data_len;
+ struct scatterlist *dsg;
+ int len, dlen;
- len = dlen - plen;
- if (len > skb_tailroom(skb))
- len = skb_tailroom(skb);
+ if (unlikely(err))
+ goto out_free_req;
- __skb_put(skb, len);
+ extra = acomp_request_extra(req);
+ dsg = extra->sg;
+ dlen = req->dlen;
- len += plen;
- skb_copy_to_linear_data(skb, scratch, len);
+ pskb_trim_unique(skb, 0);
+ __skb_put(skb, hlen);
- while ((scratch += len, dlen -= len) > 0) {
+ /* Only update truesize on input. */
+ if (!hlen)
+ skb->truesize += dlen - plen;
+ skb->data_len = dlen;
+ skb->len += dlen;
+
+ do {
skb_frag_t *frag;
struct page *page;
- if (WARN_ON(skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS))
- return -EMSGSIZE;
-
frag = skb_shinfo(skb)->frags + skb_shinfo(skb)->nr_frags;
- page = alloc_page(GFP_ATOMIC);
-
- if (!page)
- return -ENOMEM;
+ page = sg_page(dsg);
+ dsg = sg_next(dsg);
len = PAGE_SIZE;
if (dlen < len)
len = dlen;
skb_frag_fill_page_desc(frag, page, 0, len);
- memcpy(skb_frag_address(frag), scratch, len);
-
- skb->truesize += len;
- skb->data_len += len;
- skb->len += len;
skb_shinfo(skb)->nr_frags++;
- }
+ } while ((dlen -= len));
- return 0;
+ for (; dsg; dsg = sg_next(dsg))
+ __free_page(sg_page(dsg));
+
+out_free_req:
+ acomp_request_free(req);
+ return err;
+}
+
+static int ipcomp_input_done2(struct sk_buff *skb, int err)
+{
+ struct ip_comp_hdr *ipch = ip_comp_hdr(skb);
+ const int plen = skb->len;
+
+ skb_reset_transport_header(skb);
+
+ return ipcomp_post_acomp(skb, err, 0) ?:
+ skb->len < (plen + sizeof(ip_comp_hdr)) ? -EINVAL :
+ ipch->nexthdr;
+}
+
+static void ipcomp_input_done(void *data, int err)
+{
+ struct sk_buff *skb = data;
+
+ xfrm_input_resume(skb, ipcomp_input_done2(skb, err));
+}
+
+static struct acomp_req *ipcomp_setup_req(struct xfrm_state *x,
+ struct sk_buff *skb, int minhead,
+ int dlen)
+{
+ const int dnfrags = min(MAX_SKB_FRAGS, 16);
+ struct ipcomp_data *ipcd = x->data;
+ struct ipcomp_req_extra *extra;
+ struct scatterlist *sg, *dsg;
+ const int plen = skb->len;
+ struct crypto_acomp *tfm;
+ struct acomp_req *req;
+ int nfrags;
+ int total;
+ int err;
+ int i;
+
+ ipcomp_cb(skb)->req = NULL;
+
+ do {
+ struct sk_buff *trailer;
+
+ if (skb->len > PAGE_SIZE) {
+ if (skb_linearize_cow(skb))
+ return ERR_PTR(-ENOMEM);
+ nfrags = 1;
+ break;
+ }
+
+ if (!skb_cloned(skb) && skb_headlen(skb) >= minhead) {
+ if (!skb_is_nonlinear(skb)) {
+ nfrags = 1;
+ break;
+ } else if (!skb_has_frag_list(skb)) {
+ nfrags = skb_shinfo(skb)->nr_frags;
+ nfrags++;
+ break;
+ }
+ }
+
+ nfrags = skb_cow_data(skb, skb_headlen(skb) < minhead ?
+ minhead - skb_headlen(skb) : 0,
+ &trailer);
+ if (nfrags < 0)
+ return ERR_PTR(nfrags);
+ } while (0);
+
+ tfm = ipcd->tfm;
+ req = acomp_request_alloc_extra(
+ tfm, sizeof(*extra) + sizeof(*sg) * (nfrags + dnfrags),
+ GFP_ATOMIC);
+ ipcomp_cb(skb)->req = req;
+ if (!req)
+ return ERR_PTR(-ENOMEM);
+
+ extra = acomp_request_extra(req);
+ extra->x = x;
+
+ dsg = extra->sg;
+ sg = dsg + dnfrags;
+ sg_init_table(sg, nfrags);
+ err = skb_to_sgvec(skb, sg, 0, plen);
+ if (unlikely(err < 0))
+ return ERR_PTR(err);
+
+ sg_init_table(dsg, dnfrags);
+ total = 0;
+ for (i = 0; i < dnfrags && total < dlen; i++) {
+ struct page *page;
+
+ page = alloc_page(GFP_ATOMIC);
+ if (!page)
+ break;
+ sg_set_page(dsg + i, page, PAGE_SIZE, 0);
+ total += PAGE_SIZE;
+ }
+ if (!i)
+ return ERR_PTR(-ENOMEM);
+ sg_mark_end(dsg + i - 1);
+
+ acomp_request_set_params(req, sg, dsg, plen, dlen);
+
+ return req;
+}
+
+static int ipcomp_decompress(struct xfrm_state *x, struct sk_buff *skb)
+{
+ struct acomp_req *req;
+ int err;
+
+ req = ipcomp_setup_req(x, skb, 0, IPCOMP_SCRATCH_SIZE);
+ err = PTR_ERR(req);
+ if (IS_ERR(req))
+ goto out;
+
+ acomp_request_set_callback(req, 0, ipcomp_input_done, skb);
+ err = crypto_acomp_decompress(req);
+ if (err == -EINPROGRESS)
+ return err;
+
+out:
+ return ipcomp_input_done2(skb, err);
}
int ipcomp_input(struct xfrm_state *x, struct sk_buff *skb)
{
- int nexthdr;
- int err = -ENOMEM;
- struct ip_comp_hdr *ipch;
+ struct ip_comp_hdr *ipch __maybe_unused;
if (!pskb_may_pull(skb, sizeof(*ipch)))
return -EINVAL;
- if (skb_linearize_cow(skb))
- goto out;
-
skb->ip_summed = CHECKSUM_NONE;
/* Remove ipcomp header and decompress original payload */
- ipch = (void *)skb->data;
- nexthdr = ipch->nexthdr;
-
- skb->transport_header = skb->network_header + sizeof(*ipch);
__skb_pull(skb, sizeof(*ipch));
- err = ipcomp_decompress(x, skb);
- if (err)
- goto out;
- err = nexthdr;
-
-out:
- return err;
+ return ipcomp_decompress(x, skb);
}
EXPORT_SYMBOL_GPL(ipcomp_input);
-static int ipcomp_compress(struct xfrm_state *x, struct sk_buff *skb)
+static int ipcomp_output_push(struct sk_buff *skb)
{
- struct ipcomp_data *ipcd = x->data;
- const int plen = skb->len;
- int dlen = IPCOMP_SCRATCH_SIZE;
- u8 *start = skb->data;
- struct crypto_comp *tfm;
- 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);
- if (err)
- goto out;
-
- if ((dlen + sizeof(struct ip_comp_hdr)) >= plen) {
- err = -EMSGSIZE;
- goto out;
- }
-
- memcpy(start + sizeof(struct ip_comp_hdr), scratch, dlen);
- local_bh_enable();
-
- pskb_trim(skb, dlen + sizeof(struct ip_comp_hdr));
+ skb_push(skb, -skb_network_offset(skb));
return 0;
-
-out:
- local_bh_enable();
- return err;
}
-int ipcomp_output(struct xfrm_state *x, struct sk_buff *skb)
+static int ipcomp_output_done2(struct xfrm_state *x, struct sk_buff *skb,
+ int err)
{
- int err;
struct ip_comp_hdr *ipch;
- struct ipcomp_data *ipcd = x->data;
- if (skb->len < ipcd->threshold) {
- /* Don't bother compressing */
+ err = ipcomp_post_acomp(skb, err, sizeof(*ipch));
+ if (err)
goto out_ok;
- }
-
- if (skb_linearize_cow(skb))
- goto out_ok;
-
- err = ipcomp_compress(x, skb);
-
- if (err) {
- goto out_ok;
- }
/* Install ipcomp header, convert into ipcomp datagram. */
ipch = ip_comp_hdr(skb);
@@ -182,135 +253,59 @@ int ipcomp_output(struct xfrm_state *x, struct sk_buff *skb)
ipch->cpi = htons((u16 )ntohl(x->id.spi));
*skb_mac_header(skb) = IPPROTO_COMP;
out_ok:
- skb_push(skb, -skb_network_offset(skb));
- return 0;
+ return ipcomp_output_push(skb);
+}
+
+static void ipcomp_output_done(void *data, int err)
+{
+ struct ipcomp_req_extra *extra;
+ struct sk_buff *skb = data;
+ struct acomp_req *req;
+
+ req = ipcomp_cb(skb)->req;
+ extra = acomp_request_extra(req);
+
+ xfrm_output_resume(skb_to_full_sk(skb), skb,
+ ipcomp_output_done2(extra->x, skb, err));
+}
+
+static int ipcomp_compress(struct xfrm_state *x, struct sk_buff *skb)
+{
+ struct ip_comp_hdr *ipch __maybe_unused;
+ struct acomp_req *req;
+ int err;
+
+ req = ipcomp_setup_req(x, skb, sizeof(*ipch),
+ skb->len - sizeof(*ipch));
+ err = PTR_ERR(req);
+ if (IS_ERR(req))
+ goto out;
+
+ acomp_request_set_callback(req, 0, ipcomp_output_done, skb);
+ err = crypto_acomp_compress(req);
+ if (err == -EINPROGRESS)
+ return err;
+
+out:
+ return ipcomp_output_done2(x, skb, err);
+}
+
+int ipcomp_output(struct xfrm_state *x, struct sk_buff *skb)
+{
+ struct ipcomp_data *ipcd = x->data;
+
+ if (skb->len < ipcd->threshold) {
+ /* Don't bother compressing */
+ return ipcomp_output_push(skb);
+ }
+
+ return ipcomp_compress(x, skb);
}
EXPORT_SYMBOL_GPL(ipcomp_output);
-static void ipcomp_free_scratches(void)
-{
- int i;
- void * __percpu *scratches;
-
- if (--ipcomp_scratch_users)
- return;
-
- scratches = ipcomp_scratches;
- if (!scratches)
- return;
-
- for_each_possible_cpu(i)
- vfree(*per_cpu_ptr(scratches, i));
-
- free_percpu(scratches);
- ipcomp_scratches = NULL;
-}
-
-static void * __percpu *ipcomp_alloc_scratches(void)
-{
- void * __percpu *scratches;
- int i;
-
- if (ipcomp_scratch_users++)
- return ipcomp_scratches;
-
- scratches = alloc_percpu(void *);
- if (!scratches)
- return NULL;
-
- ipcomp_scratches = scratches;
-
- for_each_possible_cpu(i) {
- void *scratch;
-
- scratch = vmalloc_node(IPCOMP_SCRATCH_SIZE, cpu_to_node(i));
- if (!scratch)
- return NULL;
- *per_cpu_ptr(scratches, i) = scratch;
- }
-
- return scratches;
-}
-
-static void ipcomp_free_tfms(struct crypto_comp * __percpu *tfms)
-{
- struct ipcomp_tfms *pos;
- int cpu;
-
- list_for_each_entry(pos, &ipcomp_tfms_list, list) {
- if (pos->tfms == tfms)
- break;
- }
-
- WARN_ON(list_entry_is_head(pos, &ipcomp_tfms_list, list));
-
- if (--pos->users)
- return;
-
- list_del(&pos->list);
- kfree(pos);
-
- if (!tfms)
- return;
-
- for_each_possible_cpu(cpu) {
- struct crypto_comp *tfm = *per_cpu_ptr(tfms, cpu);
- crypto_free_comp(tfm);
- }
- free_percpu(tfms);
-}
-
-static struct crypto_comp * __percpu *ipcomp_alloc_tfms(const char *alg_name)
-{
- struct ipcomp_tfms *pos;
- struct crypto_comp * __percpu *tfms;
- int cpu;
-
-
- list_for_each_entry(pos, &ipcomp_tfms_list, list) {
- struct crypto_comp *tfm;
-
- /* This can be any valid CPU ID so we don't need locking. */
- tfm = this_cpu_read(*pos->tfms);
-
- if (!strcmp(crypto_comp_name(tfm), alg_name)) {
- pos->users++;
- return pos->tfms;
- }
- }
-
- pos = kmalloc(sizeof(*pos), GFP_KERNEL);
- if (!pos)
- return NULL;
-
- pos->users = 1;
- INIT_LIST_HEAD(&pos->list);
- list_add(&pos->list, &ipcomp_tfms_list);
-
- pos->tfms = tfms = alloc_percpu(struct crypto_comp *);
- if (!tfms)
- goto error;
-
- for_each_possible_cpu(cpu) {
- struct crypto_comp *tfm = crypto_alloc_comp(alg_name, 0,
- CRYPTO_ALG_ASYNC);
- if (IS_ERR(tfm))
- goto error;
- *per_cpu_ptr(tfms, cpu) = tfm;
- }
-
- return tfms;
-
-error:
- ipcomp_free_tfms(tfms);
- return NULL;
-}
-
static void ipcomp_free_data(struct ipcomp_data *ipcd)
{
- if (ipcd->tfms)
- ipcomp_free_tfms(ipcd->tfms);
- ipcomp_free_scratches();
+ crypto_free_acomp(ipcd->tfm);
}
void ipcomp_destroy(struct xfrm_state *x)
@@ -319,9 +314,7 @@ void ipcomp_destroy(struct xfrm_state *x)
if (!ipcd)
return;
xfrm_state_delete_tunnel(x);
- mutex_lock(&ipcomp_resource_mutex);
ipcomp_free_data(ipcd);
- mutex_unlock(&ipcomp_resource_mutex);
kfree(ipcd);
}
EXPORT_SYMBOL_GPL(ipcomp_destroy);
@@ -348,15 +341,10 @@ int ipcomp_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack)
if (!ipcd)
goto out;
- mutex_lock(&ipcomp_resource_mutex);
- if (!ipcomp_alloc_scratches())
+ ipcd->tfm = crypto_alloc_acomp(x->calg->alg_name, 0, 0);
+ if (IS_ERR(ipcd->tfm))
goto error;
- ipcd->tfms = ipcomp_alloc_tfms(x->calg->alg_name);
- if (!ipcd->tfms)
- goto error;
- mutex_unlock(&ipcomp_resource_mutex);
-
calg_desc = xfrm_calg_get_byname(x->calg->alg_name, 0);
BUG_ON(!calg_desc);
ipcd->threshold = calg_desc->uinfo.comp.threshold;
@@ -367,7 +355,6 @@ int ipcomp_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack)
error:
ipcomp_free_data(ipcd);
- mutex_unlock(&ipcomp_resource_mutex);
kfree(ipcd);
goto out;
}
--
2.39.5
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [v5 PATCH 12/14] PM: hibernate: Use crypto_acomp interface
2025-03-15 10:30 [v5 PATCH 00/14] crypto: acomp - Add virtual address and folio support Herbert Xu
` (10 preceding siblings ...)
2025-03-15 10:30 ` [v5 PATCH 11/14] xfrm: ipcomp: Use crypto_acomp interface Herbert Xu
@ 2025-03-15 10:30 ` Herbert Xu
2025-03-15 10:30 ` [v5 PATCH 13/14] ubifs: " Herbert Xu
2025-03-15 10:30 ` [v5 PATCH 14/14] ubifs: Pass folios to acomp Herbert Xu
13 siblings, 0 replies; 24+ messages in thread
From: Herbert Xu @ 2025-03-15 10:30 UTC (permalink / raw)
To: Linux Crypto Mailing List
Cc: Richard Weinberger, Zhihao Cheng, linux-mtd, Rafael J. Wysocki,
Pavel Machek, linux-pm, Steffen Klassert, netdev
Replace the legacy crypto compression interface with the new acomp
interface.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Acked-by: Rafael J. Wysocki <rafael@kernel.org>
---
kernel/power/hibernate.c | 5 ++--
kernel/power/swap.c | 58 +++++++++++++++++++++++++++-------------
2 files changed, 42 insertions(+), 21 deletions(-)
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index 10a01af63a80..12051ff00839 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -11,6 +11,7 @@
#define pr_fmt(fmt) "PM: hibernation: " fmt
+#include <crypto/acompress.h>
#include <linux/blkdev.h>
#include <linux/export.h>
#include <linux/suspend.h>
@@ -757,7 +758,7 @@ int hibernate(void)
*/
if (!nocompress) {
strscpy(hib_comp_algo, hibernate_compressor, sizeof(hib_comp_algo));
- if (crypto_has_comp(hib_comp_algo, 0, 0) != 1) {
+ if (!crypto_has_acomp(hib_comp_algo, 0, CRYPTO_ALG_ASYNC)) {
pr_err("%s compression is not available\n", hib_comp_algo);
return -EOPNOTSUPP;
}
@@ -1008,7 +1009,7 @@ static int software_resume(void)
strscpy(hib_comp_algo, COMPRESSION_ALGO_LZ4, sizeof(hib_comp_algo));
else
strscpy(hib_comp_algo, COMPRESSION_ALGO_LZO, sizeof(hib_comp_algo));
- if (crypto_has_comp(hib_comp_algo, 0, 0) != 1) {
+ if (!crypto_has_acomp(hib_comp_algo, 0, CRYPTO_ALG_ASYNC)) {
pr_err("%s compression is not available\n", hib_comp_algo);
error = -EOPNOTSUPP;
goto Unlock;
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 82b884b67152..80ff5f933a62 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -12,6 +12,7 @@
#define pr_fmt(fmt) "PM: " fmt
+#include <crypto/acompress.h>
#include <linux/module.h>
#include <linux/file.h>
#include <linux/delay.h>
@@ -635,7 +636,8 @@ static int crc32_threadfn(void *data)
*/
struct cmp_data {
struct task_struct *thr; /* thread */
- struct crypto_comp *cc; /* crypto compressor stream */
+ struct crypto_acomp *cc; /* crypto compressor */
+ struct acomp_req *cr; /* crypto request */
atomic_t ready; /* ready to start flag */
atomic_t stop; /* ready to stop flag */
int ret; /* return code */
@@ -656,7 +658,6 @@ static atomic_t compressed_size = ATOMIC_INIT(0);
static int compress_threadfn(void *data)
{
struct cmp_data *d = data;
- unsigned int cmp_len = 0;
while (1) {
wait_event(d->go, atomic_read_acquire(&d->ready) ||
@@ -670,11 +671,13 @@ static int compress_threadfn(void *data)
}
atomic_set(&d->ready, 0);
- cmp_len = CMP_SIZE - CMP_HEADER;
- d->ret = crypto_comp_compress(d->cc, d->unc, d->unc_len,
- d->cmp + CMP_HEADER,
- &cmp_len);
- d->cmp_len = cmp_len;
+ acomp_request_set_callback(d->cr, CRYPTO_TFM_REQ_MAY_SLEEP,
+ NULL, NULL);
+ acomp_request_set_src_nondma(d->cr, d->unc, d->unc_len);
+ acomp_request_set_dst_nondma(d->cr, d->cmp + CMP_HEADER,
+ CMP_SIZE - CMP_HEADER);
+ d->ret = crypto_acomp_compress(d->cr);
+ d->cmp_len = d->cr->dlen;
atomic_set(&compressed_size, atomic_read(&compressed_size) + d->cmp_len);
atomic_set_release(&d->stop, 1);
@@ -745,13 +748,20 @@ static int save_compressed_image(struct swap_map_handle *handle,
init_waitqueue_head(&data[thr].go);
init_waitqueue_head(&data[thr].done);
- data[thr].cc = crypto_alloc_comp(hib_comp_algo, 0, 0);
+ data[thr].cc = crypto_alloc_acomp(hib_comp_algo, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR_OR_NULL(data[thr].cc)) {
pr_err("Could not allocate comp stream %ld\n", PTR_ERR(data[thr].cc));
ret = -EFAULT;
goto out_clean;
}
+ data[thr].cr = acomp_request_alloc(data[thr].cc);
+ if (!data[thr].cr) {
+ pr_err("Could not allocate comp request\n");
+ ret = -ENOMEM;
+ goto out_clean;
+ }
+
data[thr].thr = kthread_run(compress_threadfn,
&data[thr],
"image_compress/%u", thr);
@@ -899,8 +909,8 @@ static int save_compressed_image(struct swap_map_handle *handle,
for (thr = 0; thr < nr_threads; thr++) {
if (data[thr].thr)
kthread_stop(data[thr].thr);
- if (data[thr].cc)
- crypto_free_comp(data[thr].cc);
+ acomp_request_free(data[thr].cr);
+ crypto_free_acomp(data[thr].cc);
}
vfree(data);
}
@@ -1142,7 +1152,8 @@ static int load_image(struct swap_map_handle *handle,
*/
struct dec_data {
struct task_struct *thr; /* thread */
- struct crypto_comp *cc; /* crypto compressor stream */
+ struct crypto_acomp *cc; /* crypto compressor */
+ struct acomp_req *cr; /* crypto request */
atomic_t ready; /* ready to start flag */
atomic_t stop; /* ready to stop flag */
int ret; /* return code */
@@ -1160,7 +1171,6 @@ struct dec_data {
static int decompress_threadfn(void *data)
{
struct dec_data *d = data;
- unsigned int unc_len = 0;
while (1) {
wait_event(d->go, atomic_read_acquire(&d->ready) ||
@@ -1174,10 +1184,13 @@ static int decompress_threadfn(void *data)
}
atomic_set(&d->ready, 0);
- unc_len = UNC_SIZE;
- d->ret = crypto_comp_decompress(d->cc, d->cmp + CMP_HEADER, d->cmp_len,
- d->unc, &unc_len);
- d->unc_len = unc_len;
+ acomp_request_set_callback(d->cr, CRYPTO_TFM_REQ_MAY_SLEEP,
+ NULL, NULL);
+ acomp_request_set_src_nondma(d->cr, d->cmp + CMP_HEADER,
+ d->cmp_len);
+ acomp_request_set_dst_nondma(d->cr, d->unc, UNC_SIZE);
+ d->ret = crypto_acomp_decompress(d->cr);
+ d->unc_len = d->cr->dlen;
if (clean_pages_on_decompress)
flush_icache_range((unsigned long)d->unc,
@@ -1254,13 +1267,20 @@ static int load_compressed_image(struct swap_map_handle *handle,
init_waitqueue_head(&data[thr].go);
init_waitqueue_head(&data[thr].done);
- data[thr].cc = crypto_alloc_comp(hib_comp_algo, 0, 0);
+ data[thr].cc = crypto_alloc_acomp(hib_comp_algo, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR_OR_NULL(data[thr].cc)) {
pr_err("Could not allocate comp stream %ld\n", PTR_ERR(data[thr].cc));
ret = -EFAULT;
goto out_clean;
}
+ data[thr].cr = acomp_request_alloc(data[thr].cc);
+ if (!data[thr].cr) {
+ pr_err("Could not allocate comp request\n");
+ ret = -ENOMEM;
+ goto out_clean;
+ }
+
data[thr].thr = kthread_run(decompress_threadfn,
&data[thr],
"image_decompress/%u", thr);
@@ -1507,8 +1527,8 @@ static int load_compressed_image(struct swap_map_handle *handle,
for (thr = 0; thr < nr_threads; thr++) {
if (data[thr].thr)
kthread_stop(data[thr].thr);
- if (data[thr].cc)
- crypto_free_comp(data[thr].cc);
+ acomp_request_free(data[thr].cr);
+ crypto_free_acomp(data[thr].cc);
}
vfree(data);
}
--
2.39.5
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [v5 PATCH 13/14] ubifs: Use crypto_acomp interface
2025-03-15 10:30 [v5 PATCH 00/14] crypto: acomp - Add virtual address and folio support Herbert Xu
` (11 preceding siblings ...)
2025-03-15 10:30 ` [v5 PATCH 12/14] PM: hibernate: " Herbert Xu
@ 2025-03-15 10:30 ` Herbert Xu
2025-03-19 9:39 ` Zhihao Cheng
2025-03-15 10:30 ` [v5 PATCH 14/14] ubifs: Pass folios to acomp Herbert Xu
13 siblings, 1 reply; 24+ messages in thread
From: Herbert Xu @ 2025-03-15 10:30 UTC (permalink / raw)
To: Linux Crypto Mailing List
Cc: Richard Weinberger, Zhihao Cheng, linux-mtd, Rafael J. Wysocki,
Pavel Machek, linux-pm, Steffen Klassert, netdev
Replace the legacy crypto compression interface with the new acomp
interface.
Remove the compression mutexes and the overallocation for memory
(the offender LZO has been fixed).
Cap the output buffer length for compression to eliminate the
post-compression check for UBIFS_MIN_COMPRESS_DIFF.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
fs/ubifs/compress.c | 106 ++++++++++++++++++++++++++------------------
fs/ubifs/journal.c | 2 +-
fs/ubifs/ubifs.h | 15 +------
3 files changed, 67 insertions(+), 56 deletions(-)
diff --git a/fs/ubifs/compress.c b/fs/ubifs/compress.c
index 0b48cbab8a3d..a241ba01c9a8 100644
--- a/fs/ubifs/compress.c
+++ b/fs/ubifs/compress.c
@@ -15,7 +15,7 @@
* decompression.
*/
-#include <linux/crypto.h>
+#include <crypto/acompress.h>
#include "ubifs.h"
/* Fake description object for the "none" compressor */
@@ -26,11 +26,8 @@ static struct ubifs_compressor none_compr = {
};
#ifdef CONFIG_UBIFS_FS_LZO
-static DEFINE_MUTEX(lzo_mutex);
-
static struct ubifs_compressor lzo_compr = {
.compr_type = UBIFS_COMPR_LZO,
- .comp_mutex = &lzo_mutex,
.name = "lzo",
.capi_name = "lzo",
};
@@ -42,13 +39,8 @@ static struct ubifs_compressor lzo_compr = {
#endif
#ifdef CONFIG_UBIFS_FS_ZLIB
-static DEFINE_MUTEX(deflate_mutex);
-static DEFINE_MUTEX(inflate_mutex);
-
static struct ubifs_compressor zlib_compr = {
.compr_type = UBIFS_COMPR_ZLIB,
- .comp_mutex = &deflate_mutex,
- .decomp_mutex = &inflate_mutex,
.name = "zlib",
.capi_name = "deflate",
};
@@ -60,13 +52,8 @@ static struct ubifs_compressor zlib_compr = {
#endif
#ifdef CONFIG_UBIFS_FS_ZSTD
-static DEFINE_MUTEX(zstd_enc_mutex);
-static DEFINE_MUTEX(zstd_dec_mutex);
-
static struct ubifs_compressor zstd_compr = {
.compr_type = UBIFS_COMPR_ZSTD,
- .comp_mutex = &zstd_enc_mutex,
- .decomp_mutex = &zstd_dec_mutex,
.name = "zstd",
.capi_name = "zstd",
};
@@ -80,6 +67,30 @@ static struct ubifs_compressor zstd_compr = {
/* All UBIFS compressors */
struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
+static int ubifs_compress_req(const struct ubifs_info *c,
+ struct acomp_req *req,
+ void *out_buf, int *out_len,
+ const char *compr_name)
+{
+ struct crypto_wait wait;
+ int in_len = req->slen;
+ int dlen = *out_len;
+ int err;
+
+ dlen = min(dlen, in_len - UBIFS_MIN_COMPRESS_DIFF);
+
+ crypto_init_wait(&wait);
+ acomp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+ crypto_req_done, &wait);
+ acomp_request_set_dst_dma(req, out_buf, dlen);
+ err = crypto_acomp_compress(req);
+ err = crypto_wait_req(err, &wait);
+ *out_len = req->dlen;
+ acomp_request_free(req);
+
+ return err;
+}
+
/**
* ubifs_compress - compress data.
* @c: UBIFS file-system description object
@@ -112,23 +123,14 @@ void ubifs_compress(const struct ubifs_info *c, const void *in_buf,
if (in_len < UBIFS_MIN_COMPR_LEN)
goto no_compr;
- if (compr->comp_mutex)
- mutex_lock(compr->comp_mutex);
- err = crypto_comp_compress(compr->cc, in_buf, in_len, out_buf,
- (unsigned int *)out_len);
- if (compr->comp_mutex)
- mutex_unlock(compr->comp_mutex);
- if (unlikely(err)) {
- ubifs_warn(c, "cannot compress %d bytes, compressor %s, error %d, leave data uncompressed",
- in_len, compr->name, err);
- goto no_compr;
+ {
+ ACOMP_REQUEST_ALLOC(req, compr->cc, GFP_NOFS | __GFP_NOWARN);
+
+ acomp_request_set_src_nondma(req, in_buf, in_len);
+ err = ubifs_compress_req(c, req, out_buf, out_len, compr->name);
}
- /*
- * If the data compressed only slightly, it is better to leave it
- * uncompressed to improve read speed.
- */
- if (in_len - *out_len < UBIFS_MIN_COMPRESS_DIFF)
+ if (err)
goto no_compr;
return;
@@ -139,6 +141,31 @@ void ubifs_compress(const struct ubifs_info *c, const void *in_buf,
*compr_type = UBIFS_COMPR_NONE;
}
+static int ubifs_decompress_req(const struct ubifs_info *c,
+ struct acomp_req *req,
+ const void *in_buf, int in_len, int *out_len,
+ const char *compr_name)
+{
+ struct crypto_wait wait;
+ int err;
+
+ crypto_init_wait(&wait);
+ acomp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+ crypto_req_done, &wait);
+ acomp_request_set_src_dma(req, in_buf, in_len);
+ err = crypto_acomp_decompress(req);
+ err = crypto_wait_req(err, &wait);
+ *out_len = req->dlen;
+
+ if (err)
+ ubifs_err(c, "cannot decompress %d bytes, compressor %s, error %d",
+ in_len, compr_name, err);
+
+ acomp_request_free(req);
+
+ return err;
+}
+
/**
* ubifs_decompress - decompress data.
* @c: UBIFS file-system description object
@@ -155,7 +182,6 @@ void ubifs_compress(const struct ubifs_info *c, const void *in_buf,
int ubifs_decompress(const struct ubifs_info *c, const void *in_buf,
int in_len, void *out_buf, int *out_len, int compr_type)
{
- int err;
struct ubifs_compressor *compr;
if (unlikely(compr_type < 0 || compr_type >= UBIFS_COMPR_TYPES_CNT)) {
@@ -176,17 +202,13 @@ int ubifs_decompress(const struct ubifs_info *c, const void *in_buf,
return 0;
}
- if (compr->decomp_mutex)
- mutex_lock(compr->decomp_mutex);
- err = crypto_comp_decompress(compr->cc, in_buf, in_len, out_buf,
- (unsigned int *)out_len);
- if (compr->decomp_mutex)
- mutex_unlock(compr->decomp_mutex);
- if (err)
- ubifs_err(c, "cannot decompress %d bytes, compressor %s, error %d",
- in_len, compr->name, err);
+ {
+ ACOMP_REQUEST_ALLOC(req, compr->cc, GFP_NOFS | __GFP_NOWARN);
- return err;
+ acomp_request_set_dst_nondma(req, out_buf, *out_len);
+ return ubifs_decompress_req(c, req, in_buf, in_len, out_len,
+ compr->name);
+ }
}
/**
@@ -199,7 +221,7 @@ int ubifs_decompress(const struct ubifs_info *c, const void *in_buf,
static int __init compr_init(struct ubifs_compressor *compr)
{
if (compr->capi_name) {
- compr->cc = crypto_alloc_comp(compr->capi_name, 0, 0);
+ compr->cc = crypto_alloc_acomp(compr->capi_name, 0, 0);
if (IS_ERR(compr->cc)) {
pr_err("UBIFS error (pid %d): cannot initialize compressor %s, error %ld",
current->pid, compr->name, PTR_ERR(compr->cc));
@@ -218,7 +240,7 @@ static int __init compr_init(struct ubifs_compressor *compr)
static void compr_exit(struct ubifs_compressor *compr)
{
if (compr->capi_name)
- crypto_free_comp(compr->cc);
+ crypto_free_acomp(compr->cc);
}
/**
diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c
index 36ba79fbd2ff..7629ca9ecfe8 100644
--- a/fs/ubifs/journal.c
+++ b/fs/ubifs/journal.c
@@ -1625,7 +1625,7 @@ static int truncate_data_node(const struct ubifs_info *c, const struct inode *in
int err, dlen, compr_type, out_len, data_size;
out_len = le32_to_cpu(dn->size);
- buf = kmalloc_array(out_len, WORST_COMPR_FACTOR, GFP_NOFS);
+ buf = kmalloc(out_len, GFP_NOFS);
if (!buf)
return -ENOMEM;
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 3375bbe0508c..7d0aaf5d2e23 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -124,13 +124,6 @@
#define OLD_ZNODE_AGE 20
#define YOUNG_ZNODE_AGE 5
-/*
- * Some compressors, like LZO, may end up with more data then the input buffer.
- * So UBIFS always allocates larger output buffer, to be sure the compressor
- * will not corrupt memory in case of worst case compression.
- */
-#define WORST_COMPR_FACTOR 2
-
#ifdef CONFIG_FS_ENCRYPTION
#define UBIFS_CIPHER_BLOCK_SIZE FSCRYPT_CONTENTS_ALIGNMENT
#else
@@ -141,7 +134,7 @@
* How much memory is needed for a buffer where we compress a data node.
*/
#define COMPRESSED_DATA_NODE_BUF_SZ \
- (UBIFS_DATA_NODE_SZ + UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR)
+ (UBIFS_DATA_NODE_SZ + UBIFS_BLOCK_SIZE)
/* Maximum expected tree height for use by bottom_up_buf */
#define BOTTOM_UP_HEIGHT 64
@@ -835,16 +828,12 @@ struct ubifs_node_range {
* struct ubifs_compressor - UBIFS compressor description structure.
* @compr_type: compressor type (%UBIFS_COMPR_LZO, etc)
* @cc: cryptoapi compressor handle
- * @comp_mutex: mutex used during compression
- * @decomp_mutex: mutex used during decompression
* @name: compressor name
* @capi_name: cryptoapi compressor name
*/
struct ubifs_compressor {
int compr_type;
- struct crypto_comp *cc;
- struct mutex *comp_mutex;
- struct mutex *decomp_mutex;
+ struct crypto_acomp *cc;
const char *name;
const char *capi_name;
};
--
2.39.5
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [v5 PATCH 14/14] ubifs: Pass folios to acomp
2025-03-15 10:30 [v5 PATCH 00/14] crypto: acomp - Add virtual address and folio support Herbert Xu
` (12 preceding siblings ...)
2025-03-15 10:30 ` [v5 PATCH 13/14] ubifs: " Herbert Xu
@ 2025-03-15 10:30 ` Herbert Xu
2025-03-19 9:44 ` Zhihao Cheng
13 siblings, 1 reply; 24+ messages in thread
From: Herbert Xu @ 2025-03-15 10:30 UTC (permalink / raw)
To: Linux Crypto Mailing List
Cc: Richard Weinberger, Zhihao Cheng, linux-mtd, Rafael J. Wysocki,
Pavel Machek, linux-pm, Steffen Klassert, netdev
As the acomp interface supports folios, use that instead of mapping
the data in ubifs.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
fs/ubifs/compress.c | 106 +++++++++++++++++++++++++++++++++++++++++++-
fs/ubifs/file.c | 74 +++++++++++--------------------
fs/ubifs/journal.c | 9 ++--
fs/ubifs/ubifs.h | 11 ++++-
4 files changed, 145 insertions(+), 55 deletions(-)
diff --git a/fs/ubifs/compress.c b/fs/ubifs/compress.c
index a241ba01c9a8..ea6f06adcd43 100644
--- a/fs/ubifs/compress.c
+++ b/fs/ubifs/compress.c
@@ -16,6 +16,7 @@
*/
#include <crypto/acompress.h>
+#include <linux/highmem.h>
#include "ubifs.h"
/* Fake description object for the "none" compressor */
@@ -126,7 +127,7 @@ void ubifs_compress(const struct ubifs_info *c, const void *in_buf,
{
ACOMP_REQUEST_ALLOC(req, compr->cc, GFP_NOFS | __GFP_NOWARN);
- acomp_request_set_src_nondma(req, in_buf, in_len);
+ acomp_request_set_src_dma(req, in_buf, in_len);
err = ubifs_compress_req(c, req, out_buf, out_len, compr->name);
}
@@ -141,6 +142,58 @@ void ubifs_compress(const struct ubifs_info *c, const void *in_buf,
*compr_type = UBIFS_COMPR_NONE;
}
+/**
+ * ubifs_compress_folio - compress folio.
+ * @c: UBIFS file-system description object
+ * @in_folio: data to compress
+ * @in_offset: offset into @in_folio
+ * @in_len: length of the data to compress
+ * @out_buf: output buffer where compressed data should be stored
+ * @out_len: output buffer length is returned here
+ * @compr_type: type of compression to use on enter, actually used compression
+ * type on exit
+ *
+ * This function compresses input folio @in_folio of length @in_len and
+ * stores the result in the output buffer @out_buf and the resulting length
+ * in @out_len. If the input buffer does not compress, it is just copied
+ * to the @out_buf. The same happens if @compr_type is %UBIFS_COMPR_NONE
+ * or if compression error occurred.
+ *
+ * Note, if the input buffer was not compressed, it is copied to the output
+ * buffer and %UBIFS_COMPR_NONE is returned in @compr_type.
+ */
+void ubifs_compress_folio(const struct ubifs_info *c, struct folio *in_folio,
+ size_t in_offset, int in_len, void *out_buf,
+ int *out_len, int *compr_type)
+{
+ int err;
+ struct ubifs_compressor *compr = ubifs_compressors[*compr_type];
+
+ if (*compr_type == UBIFS_COMPR_NONE)
+ goto no_compr;
+
+ /* If the input data is small, do not even try to compress it */
+ if (in_len < UBIFS_MIN_COMPR_LEN)
+ goto no_compr;
+
+ {
+ ACOMP_REQUEST_ALLOC(req, compr->cc, GFP_NOFS | __GFP_NOWARN);
+
+ acomp_request_set_src_folio(req, in_folio, in_offset, in_len);
+ err = ubifs_compress_req(c, req, out_buf, out_len, compr->name);
+ }
+
+ if (err)
+ goto no_compr;
+
+ return;
+
+no_compr:
+ memcpy_from_folio(out_buf, in_folio, in_offset, in_len);
+ *out_len = in_len;
+ *compr_type = UBIFS_COMPR_NONE;
+}
+
static int ubifs_decompress_req(const struct ubifs_info *c,
struct acomp_req *req,
const void *in_buf, int in_len, int *out_len,
@@ -205,7 +258,56 @@ int ubifs_decompress(const struct ubifs_info *c, const void *in_buf,
{
ACOMP_REQUEST_ALLOC(req, compr->cc, GFP_NOFS | __GFP_NOWARN);
- acomp_request_set_dst_nondma(req, out_buf, *out_len);
+ acomp_request_set_dst_dma(req, out_buf, *out_len);
+ return ubifs_decompress_req(c, req, in_buf, in_len, out_len,
+ compr->name);
+ }
+}
+
+/**
+ * ubifs_decompress_folio - decompress folio.
+ * @c: UBIFS file-system description object
+ * @in_buf: data to decompress
+ * @in_len: length of the data to decompress
+ * @out_folio: output folio where decompressed data should
+ * @out_offset: offset into @out_folio
+ * @out_len: output length is returned here
+ * @compr_type: type of compression
+ *
+ * This function decompresses data from buffer @in_buf into folio
+ * @out_folio. The length of the uncompressed data is returned in
+ * @out_len. This functions returns %0 on success or a negative error
+ * code on failure.
+ */
+int ubifs_decompress_folio(const struct ubifs_info *c, const void *in_buf,
+ int in_len, struct folio *out_folio,
+ size_t out_offset, int *out_len, int compr_type)
+{
+ struct ubifs_compressor *compr;
+
+ if (unlikely(compr_type < 0 || compr_type >= UBIFS_COMPR_TYPES_CNT)) {
+ ubifs_err(c, "invalid compression type %d", compr_type);
+ return -EINVAL;
+ }
+
+ compr = ubifs_compressors[compr_type];
+
+ if (unlikely(!compr->capi_name)) {
+ ubifs_err(c, "%s compression is not compiled in", compr->name);
+ return -EINVAL;
+ }
+
+ if (compr_type == UBIFS_COMPR_NONE) {
+ memcpy_to_folio(out_folio, out_offset, in_buf, in_len);
+ *out_len = in_len;
+ return 0;
+ }
+
+ {
+ ACOMP_REQUEST_ALLOC(req, compr->cc, GFP_NOFS | __GFP_NOWARN);
+
+ acomp_request_set_dst_folio(req, out_folio, out_offset,
+ *out_len);
return ubifs_decompress_req(c, req, in_buf, in_len, out_len,
compr->name);
}
diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
index 5130123005e4..bf311c38d9a8 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -42,8 +42,8 @@
#include <linux/slab.h>
#include <linux/migrate.h>
-static int read_block(struct inode *inode, void *addr, unsigned int block,
- struct ubifs_data_node *dn)
+static int read_block(struct inode *inode, struct folio *folio, size_t offset,
+ unsigned int block, struct ubifs_data_node *dn)
{
struct ubifs_info *c = inode->i_sb->s_fs_info;
int err, len, out_len;
@@ -55,7 +55,7 @@ static int read_block(struct inode *inode, void *addr, unsigned int block,
if (err) {
if (err == -ENOENT)
/* Not found, so it must be a hole */
- memset(addr, 0, UBIFS_BLOCK_SIZE);
+ folio_zero_range(folio, offset, UBIFS_BLOCK_SIZE);
return err;
}
@@ -74,8 +74,8 @@ static int read_block(struct inode *inode, void *addr, unsigned int block,
}
out_len = UBIFS_BLOCK_SIZE;
- err = ubifs_decompress(c, &dn->data, dlen, addr, &out_len,
- le16_to_cpu(dn->compr_type));
+ err = ubifs_decompress_folio(c, &dn->data, dlen, folio, offset,
+ &out_len, le16_to_cpu(dn->compr_type));
if (err || len != out_len)
goto dump;
@@ -85,7 +85,7 @@ static int read_block(struct inode *inode, void *addr, unsigned int block,
* appending data). Ensure that the remainder is zeroed out.
*/
if (len < UBIFS_BLOCK_SIZE)
- memset(addr + len, 0, UBIFS_BLOCK_SIZE - len);
+ folio_zero_range(folio, offset + len, UBIFS_BLOCK_SIZE - len);
return 0;
@@ -98,27 +98,25 @@ static int read_block(struct inode *inode, void *addr, unsigned int block,
static int do_readpage(struct folio *folio)
{
- void *addr;
int err = 0, i;
unsigned int block, beyond;
struct ubifs_data_node *dn = NULL;
struct inode *inode = folio->mapping->host;
struct ubifs_info *c = inode->i_sb->s_fs_info;
loff_t i_size = i_size_read(inode);
+ size_t offset = 0;
dbg_gen("ino %lu, pg %lu, i_size %lld, flags %#lx",
inode->i_ino, folio->index, i_size, folio->flags);
ubifs_assert(c, !folio_test_checked(folio));
ubifs_assert(c, !folio->private);
- addr = kmap_local_folio(folio, 0);
-
block = folio->index << UBIFS_BLOCKS_PER_PAGE_SHIFT;
beyond = (i_size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT;
if (block >= beyond) {
/* Reading beyond inode */
folio_set_checked(folio);
- addr = folio_zero_tail(folio, 0, addr);
+ folio_zero_range(folio, 0, folio_size(folio));
goto out;
}
@@ -135,9 +133,9 @@ static int do_readpage(struct folio *folio)
if (block >= beyond) {
/* Reading beyond inode */
err = -ENOENT;
- memset(addr, 0, UBIFS_BLOCK_SIZE);
+ folio_zero_range(folio, offset, UBIFS_BLOCK_SIZE);
} else {
- ret = read_block(inode, addr, block, dn);
+ ret = read_block(inode, folio, offset, block, dn);
if (ret) {
err = ret;
if (err != -ENOENT)
@@ -147,17 +145,13 @@ static int do_readpage(struct folio *folio)
int ilen = i_size & (UBIFS_BLOCK_SIZE - 1);
if (ilen && ilen < dlen)
- memset(addr + ilen, 0, dlen - ilen);
+ folio_zero_range(folio, offset + ilen, dlen - ilen);
}
}
if (++i >= (UBIFS_BLOCKS_PER_PAGE << folio_order(folio)))
break;
block += 1;
- addr += UBIFS_BLOCK_SIZE;
- if (folio_test_highmem(folio) && (offset_in_page(addr) == 0)) {
- kunmap_local(addr - UBIFS_BLOCK_SIZE);
- addr = kmap_local_folio(folio, i * UBIFS_BLOCK_SIZE);
- }
+ offset += UBIFS_BLOCK_SIZE;
}
if (err) {
@@ -177,8 +171,6 @@ static int do_readpage(struct folio *folio)
kfree(dn);
if (!err)
folio_mark_uptodate(folio);
- flush_dcache_folio(folio);
- kunmap_local(addr);
return err;
}
@@ -602,18 +594,16 @@ static int populate_page(struct ubifs_info *c, struct folio *folio,
struct inode *inode = folio->mapping->host;
loff_t i_size = i_size_read(inode);
unsigned int page_block;
- void *addr, *zaddr;
+ size_t offset = 0;
pgoff_t end_index;
dbg_gen("ino %lu, pg %lu, i_size %lld, flags %#lx",
inode->i_ino, folio->index, i_size, folio->flags);
- addr = zaddr = kmap_local_folio(folio, 0);
-
end_index = (i_size - 1) >> PAGE_SHIFT;
if (!i_size || folio->index > end_index) {
hole = 1;
- addr = folio_zero_tail(folio, 0, addr);
+ folio_zero_range(folio, 0, folio_size(folio));
goto out_hole;
}
@@ -623,7 +613,7 @@ static int populate_page(struct ubifs_info *c, struct folio *folio,
if (nn >= bu->cnt) {
hole = 1;
- memset(addr, 0, UBIFS_BLOCK_SIZE);
+ folio_zero_range(folio, offset, UBIFS_BLOCK_SIZE);
} else if (key_block(c, &bu->zbranch[nn].key) == page_block) {
struct ubifs_data_node *dn;
@@ -645,13 +635,15 @@ static int populate_page(struct ubifs_info *c, struct folio *folio,
goto out_err;
}
- err = ubifs_decompress(c, &dn->data, dlen, addr, &out_len,
- le16_to_cpu(dn->compr_type));
+ err = ubifs_decompress_folio(
+ c, &dn->data, dlen, folio, offset, &out_len,
+ le16_to_cpu(dn->compr_type));
if (err || len != out_len)
goto out_err;
if (len < UBIFS_BLOCK_SIZE)
- memset(addr + len, 0, UBIFS_BLOCK_SIZE - len);
+ folio_zero_range(folio, offset + len,
+ UBIFS_BLOCK_SIZE - len);
nn += 1;
read = (i << UBIFS_BLOCK_SHIFT) + len;
@@ -660,23 +652,19 @@ static int populate_page(struct ubifs_info *c, struct folio *folio,
continue;
} else {
hole = 1;
- memset(addr, 0, UBIFS_BLOCK_SIZE);
+ folio_zero_range(folio, offset, UBIFS_BLOCK_SIZE);
}
if (++i >= UBIFS_BLOCKS_PER_PAGE)
break;
- addr += UBIFS_BLOCK_SIZE;
+ offset += UBIFS_BLOCK_SIZE;
page_block += 1;
- if (folio_test_highmem(folio) && (offset_in_page(addr) == 0)) {
- kunmap_local(addr - UBIFS_BLOCK_SIZE);
- addr = kmap_local_folio(folio, i * UBIFS_BLOCK_SIZE);
- }
}
if (end_index == folio->index) {
int len = i_size & (PAGE_SIZE - 1);
if (len && len < read)
- memset(zaddr + len, 0, read - len);
+ folio_zero_range(folio, len, read - len);
}
out_hole:
@@ -686,14 +674,10 @@ static int populate_page(struct ubifs_info *c, struct folio *folio,
}
folio_mark_uptodate(folio);
- flush_dcache_folio(folio);
- kunmap_local(addr);
*n = nn;
return 0;
out_err:
- flush_dcache_folio(folio);
- kunmap_local(addr);
ubifs_err(c, "bad data node (block %u, inode %lu)",
page_block, inode->i_ino);
return -EINVAL;
@@ -898,7 +882,6 @@ static int do_writepage(struct folio *folio, size_t len)
{
int err = 0, blen;
unsigned int block;
- void *addr;
size_t offset = 0;
union ubifs_key key;
struct inode *inode = folio->mapping->host;
@@ -913,26 +896,19 @@ static int do_writepage(struct folio *folio, size_t len)
folio_start_writeback(folio);
- addr = kmap_local_folio(folio, offset);
block = folio->index << UBIFS_BLOCKS_PER_PAGE_SHIFT;
for (;;) {
blen = min_t(size_t, len, UBIFS_BLOCK_SIZE);
data_key_init(c, &key, inode->i_ino, block);
- err = ubifs_jnl_write_data(c, inode, &key, addr, blen);
+ err = ubifs_jnl_write_data(c, inode, &key, folio, offset, blen);
if (err)
break;
len -= blen;
if (!len)
break;
block += 1;
- addr += blen;
- if (folio_test_highmem(folio) && !offset_in_page(addr)) {
- kunmap_local(addr - blen);
- offset += PAGE_SIZE;
- addr = kmap_local_folio(folio, offset);
- }
+ offset += blen;
}
- kunmap_local(addr);
if (err) {
mapping_set_error(folio->mapping, err);
ubifs_err(c, "cannot write folio %lu of inode %lu, error %d",
diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c
index 7629ca9ecfe8..ee954e64ce7f 100644
--- a/fs/ubifs/journal.c
+++ b/fs/ubifs/journal.c
@@ -845,14 +845,16 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
* @c: UBIFS file-system description object
* @inode: inode the data node belongs to
* @key: node key
- * @buf: buffer to write
+ * @folio: buffer to write
+ * @offset: offset to write at
* @len: data length (must not exceed %UBIFS_BLOCK_SIZE)
*
* This function writes a data node to the journal. Returns %0 if the data node
* was successfully written, and a negative error code in case of failure.
*/
int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
- const union ubifs_key *key, const void *buf, int len)
+ const union ubifs_key *key, struct folio *folio,
+ size_t offset, int len)
{
struct ubifs_data_node *data;
int err, lnum, offs, compr_type, out_len, compr_len, auth_len;
@@ -896,7 +898,8 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
compr_type = ui->compr_type;
out_len = compr_len = dlen - UBIFS_DATA_NODE_SZ;
- ubifs_compress(c, buf, len, &data->data, &compr_len, &compr_type);
+ ubifs_compress_folio(c, folio, offset, len, &data->data, &compr_len,
+ &compr_type);
ubifs_assert(c, compr_len <= UBIFS_BLOCK_SIZE);
if (encrypted) {
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 7d0aaf5d2e23..256dbaeeb0de 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -263,6 +263,8 @@ enum {
ASSACT_PANIC,
};
+struct folio;
+
/**
* struct ubifs_old_idx - index node obsoleted since last commit start.
* @rb: rb-tree node
@@ -1784,7 +1786,8 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
const struct fscrypt_name *nm, const struct inode *inode,
int deletion, int xent, int in_orphan);
int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
- const union ubifs_key *key, const void *buf, int len);
+ const union ubifs_key *key, struct folio *folio,
+ size_t offset, int len);
int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode);
int ubifs_jnl_delete_inode(struct ubifs_info *c, const struct inode *inode);
int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
@@ -2084,8 +2087,14 @@ int __init ubifs_compressors_init(void);
void ubifs_compressors_exit(void);
void ubifs_compress(const struct ubifs_info *c, const void *in_buf, int in_len,
void *out_buf, int *out_len, int *compr_type);
+void ubifs_compress_folio(const struct ubifs_info *c, struct folio *folio,
+ size_t offset, int in_len, void *out_buf,
+ int *out_len, int *compr_type);
int ubifs_decompress(const struct ubifs_info *c, const void *buf, int len,
void *out, int *out_len, int compr_type);
+int ubifs_decompress_folio(const struct ubifs_info *c, const void *buf,
+ int len, struct folio *folio, size_t offset,
+ int *out_len, int compr_type);
/* sysfs.c */
int ubifs_sysfs_init(void);
--
2.39.5
^ permalink raw reply related [flat|nested] 24+ messages in thread
* Re: [v5 PATCH 13/14] ubifs: Use crypto_acomp interface
2025-03-15 10:30 ` [v5 PATCH 13/14] ubifs: " Herbert Xu
@ 2025-03-19 9:39 ` Zhihao Cheng
0 siblings, 0 replies; 24+ messages in thread
From: Zhihao Cheng @ 2025-03-19 9:39 UTC (permalink / raw)
To: Herbert Xu, Linux Crypto Mailing List
Cc: Richard Weinberger, linux-mtd, Rafael J. Wysocki, Pavel Machek,
linux-pm, Steffen Klassert, netdev
在 2025/3/15 18:30, Herbert Xu 写道:
> Replace the legacy crypto compression interface with the new acomp
> interface.
>
> Remove the compression mutexes and the overallocation for memory
> (the offender LZO has been fixed).
>
> Cap the output buffer length for compression to eliminate the
> post-compression check for UBIFS_MIN_COMPRESS_DIFF.
>
> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
> ---
> fs/ubifs/compress.c | 106 ++++++++++++++++++++++++++------------------
> fs/ubifs/journal.c | 2 +-
> fs/ubifs/ubifs.h | 15 +------
> 3 files changed, 67 insertions(+), 56 deletions(-)
>
Tested-by: Zhihao Cheng <chengzhihao1@huawei.com> # For xfstests
Reviewed-by: Zhihao Cheng <chengzhihao1@huawei.com>
> diff --git a/fs/ubifs/compress.c b/fs/ubifs/compress.c
> index 0b48cbab8a3d..a241ba01c9a8 100644
> --- a/fs/ubifs/compress.c
> +++ b/fs/ubifs/compress.c
> @@ -15,7 +15,7 @@
> * decompression.
> */
>
> -#include <linux/crypto.h>
> +#include <crypto/acompress.h>
> #include "ubifs.h"
>
> /* Fake description object for the "none" compressor */
> @@ -26,11 +26,8 @@ static struct ubifs_compressor none_compr = {
> };
>
> #ifdef CONFIG_UBIFS_FS_LZO
> -static DEFINE_MUTEX(lzo_mutex);
> -
> static struct ubifs_compressor lzo_compr = {
> .compr_type = UBIFS_COMPR_LZO,
> - .comp_mutex = &lzo_mutex,
> .name = "lzo",
> .capi_name = "lzo",
> };
> @@ -42,13 +39,8 @@ static struct ubifs_compressor lzo_compr = {
> #endif
>
> #ifdef CONFIG_UBIFS_FS_ZLIB
> -static DEFINE_MUTEX(deflate_mutex);
> -static DEFINE_MUTEX(inflate_mutex);
> -
> static struct ubifs_compressor zlib_compr = {
> .compr_type = UBIFS_COMPR_ZLIB,
> - .comp_mutex = &deflate_mutex,
> - .decomp_mutex = &inflate_mutex,
> .name = "zlib",
> .capi_name = "deflate",
> };
> @@ -60,13 +52,8 @@ static struct ubifs_compressor zlib_compr = {
> #endif
>
> #ifdef CONFIG_UBIFS_FS_ZSTD
> -static DEFINE_MUTEX(zstd_enc_mutex);
> -static DEFINE_MUTEX(zstd_dec_mutex);
> -
> static struct ubifs_compressor zstd_compr = {
> .compr_type = UBIFS_COMPR_ZSTD,
> - .comp_mutex = &zstd_enc_mutex,
> - .decomp_mutex = &zstd_dec_mutex,
> .name = "zstd",
> .capi_name = "zstd",
> };
> @@ -80,6 +67,30 @@ static struct ubifs_compressor zstd_compr = {
> /* All UBIFS compressors */
> struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
>
> +static int ubifs_compress_req(const struct ubifs_info *c,
> + struct acomp_req *req,
> + void *out_buf, int *out_len,
> + const char *compr_name)
> +{
> + struct crypto_wait wait;
> + int in_len = req->slen;
> + int dlen = *out_len;
> + int err;
> +
> + dlen = min(dlen, in_len - UBIFS_MIN_COMPRESS_DIFF);
> +
> + crypto_init_wait(&wait);
> + acomp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
> + crypto_req_done, &wait);
> + acomp_request_set_dst_dma(req, out_buf, dlen);
> + err = crypto_acomp_compress(req);
> + err = crypto_wait_req(err, &wait);
> + *out_len = req->dlen;
> + acomp_request_free(req);
> +
> + return err;
> +}
> +
> /**
> * ubifs_compress - compress data.
> * @c: UBIFS file-system description object
> @@ -112,23 +123,14 @@ void ubifs_compress(const struct ubifs_info *c, const void *in_buf,
> if (in_len < UBIFS_MIN_COMPR_LEN)
> goto no_compr;
>
> - if (compr->comp_mutex)
> - mutex_lock(compr->comp_mutex);
> - err = crypto_comp_compress(compr->cc, in_buf, in_len, out_buf,
> - (unsigned int *)out_len);
> - if (compr->comp_mutex)
> - mutex_unlock(compr->comp_mutex);
> - if (unlikely(err)) {
> - ubifs_warn(c, "cannot compress %d bytes, compressor %s, error %d, leave data uncompressed",
> - in_len, compr->name, err);
> - goto no_compr;
> + {
> + ACOMP_REQUEST_ALLOC(req, compr->cc, GFP_NOFS | __GFP_NOWARN);
> +
> + acomp_request_set_src_nondma(req, in_buf, in_len);
> + err = ubifs_compress_req(c, req, out_buf, out_len, compr->name);
> }
>
> - /*
> - * If the data compressed only slightly, it is better to leave it
> - * uncompressed to improve read speed.
> - */
> - if (in_len - *out_len < UBIFS_MIN_COMPRESS_DIFF)
> + if (err)
> goto no_compr;
>
> return;
> @@ -139,6 +141,31 @@ void ubifs_compress(const struct ubifs_info *c, const void *in_buf,
> *compr_type = UBIFS_COMPR_NONE;
> }
>
> +static int ubifs_decompress_req(const struct ubifs_info *c,
> + struct acomp_req *req,
> + const void *in_buf, int in_len, int *out_len,
> + const char *compr_name)
> +{
> + struct crypto_wait wait;
> + int err;
> +
> + crypto_init_wait(&wait);
> + acomp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
> + crypto_req_done, &wait);
> + acomp_request_set_src_dma(req, in_buf, in_len);
> + err = crypto_acomp_decompress(req);
> + err = crypto_wait_req(err, &wait);
> + *out_len = req->dlen;
> +
> + if (err)
> + ubifs_err(c, "cannot decompress %d bytes, compressor %s, error %d",
> + in_len, compr_name, err);
> +
> + acomp_request_free(req);
> +
> + return err;
> +}
> +
> /**
> * ubifs_decompress - decompress data.
> * @c: UBIFS file-system description object
> @@ -155,7 +182,6 @@ void ubifs_compress(const struct ubifs_info *c, const void *in_buf,
> int ubifs_decompress(const struct ubifs_info *c, const void *in_buf,
> int in_len, void *out_buf, int *out_len, int compr_type)
> {
> - int err;
> struct ubifs_compressor *compr;
>
> if (unlikely(compr_type < 0 || compr_type >= UBIFS_COMPR_TYPES_CNT)) {
> @@ -176,17 +202,13 @@ int ubifs_decompress(const struct ubifs_info *c, const void *in_buf,
> return 0;
> }
>
> - if (compr->decomp_mutex)
> - mutex_lock(compr->decomp_mutex);
> - err = crypto_comp_decompress(compr->cc, in_buf, in_len, out_buf,
> - (unsigned int *)out_len);
> - if (compr->decomp_mutex)
> - mutex_unlock(compr->decomp_mutex);
> - if (err)
> - ubifs_err(c, "cannot decompress %d bytes, compressor %s, error %d",
> - in_len, compr->name, err);
> + {
> + ACOMP_REQUEST_ALLOC(req, compr->cc, GFP_NOFS | __GFP_NOWARN);
>
> - return err;
> + acomp_request_set_dst_nondma(req, out_buf, *out_len);
> + return ubifs_decompress_req(c, req, in_buf, in_len, out_len,
> + compr->name);
> + }
> }
>
> /**
> @@ -199,7 +221,7 @@ int ubifs_decompress(const struct ubifs_info *c, const void *in_buf,
> static int __init compr_init(struct ubifs_compressor *compr)
> {
> if (compr->capi_name) {
> - compr->cc = crypto_alloc_comp(compr->capi_name, 0, 0);
> + compr->cc = crypto_alloc_acomp(compr->capi_name, 0, 0);
> if (IS_ERR(compr->cc)) {
> pr_err("UBIFS error (pid %d): cannot initialize compressor %s, error %ld",
> current->pid, compr->name, PTR_ERR(compr->cc));
> @@ -218,7 +240,7 @@ static int __init compr_init(struct ubifs_compressor *compr)
> static void compr_exit(struct ubifs_compressor *compr)
> {
> if (compr->capi_name)
> - crypto_free_comp(compr->cc);
> + crypto_free_acomp(compr->cc);
> }
>
> /**
> diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c
> index 36ba79fbd2ff..7629ca9ecfe8 100644
> --- a/fs/ubifs/journal.c
> +++ b/fs/ubifs/journal.c
> @@ -1625,7 +1625,7 @@ static int truncate_data_node(const struct ubifs_info *c, const struct inode *in
> int err, dlen, compr_type, out_len, data_size;
>
> out_len = le32_to_cpu(dn->size);
> - buf = kmalloc_array(out_len, WORST_COMPR_FACTOR, GFP_NOFS);
> + buf = kmalloc(out_len, GFP_NOFS);
> if (!buf)
> return -ENOMEM;
>
> diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
> index 3375bbe0508c..7d0aaf5d2e23 100644
> --- a/fs/ubifs/ubifs.h
> +++ b/fs/ubifs/ubifs.h
> @@ -124,13 +124,6 @@
> #define OLD_ZNODE_AGE 20
> #define YOUNG_ZNODE_AGE 5
>
> -/*
> - * Some compressors, like LZO, may end up with more data then the input buffer.
> - * So UBIFS always allocates larger output buffer, to be sure the compressor
> - * will not corrupt memory in case of worst case compression.
> - */
> -#define WORST_COMPR_FACTOR 2
> -
> #ifdef CONFIG_FS_ENCRYPTION
> #define UBIFS_CIPHER_BLOCK_SIZE FSCRYPT_CONTENTS_ALIGNMENT
> #else
> @@ -141,7 +134,7 @@
> * How much memory is needed for a buffer where we compress a data node.
> */
> #define COMPRESSED_DATA_NODE_BUF_SZ \
> - (UBIFS_DATA_NODE_SZ + UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR)
> + (UBIFS_DATA_NODE_SZ + UBIFS_BLOCK_SIZE)
>
> /* Maximum expected tree height for use by bottom_up_buf */
> #define BOTTOM_UP_HEIGHT 64
> @@ -835,16 +828,12 @@ struct ubifs_node_range {
> * struct ubifs_compressor - UBIFS compressor description structure.
> * @compr_type: compressor type (%UBIFS_COMPR_LZO, etc)
> * @cc: cryptoapi compressor handle
> - * @comp_mutex: mutex used during compression
> - * @decomp_mutex: mutex used during decompression
> * @name: compressor name
> * @capi_name: cryptoapi compressor name
> */
> struct ubifs_compressor {
> int compr_type;
> - struct crypto_comp *cc;
> - struct mutex *comp_mutex;
> - struct mutex *decomp_mutex;
> + struct crypto_acomp *cc;
> const char *name;
> const char *capi_name;
> };
>
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [v5 PATCH 14/14] ubifs: Pass folios to acomp
2025-03-15 10:30 ` [v5 PATCH 14/14] ubifs: Pass folios to acomp Herbert Xu
@ 2025-03-19 9:44 ` Zhihao Cheng
2025-03-19 9:46 ` Herbert Xu
0 siblings, 1 reply; 24+ messages in thread
From: Zhihao Cheng @ 2025-03-19 9:44 UTC (permalink / raw)
To: Herbert Xu, Linux Crypto Mailing List
Cc: Richard Weinberger, linux-mtd, Rafael J. Wysocki, Pavel Machek,
linux-pm, Steffen Klassert, netdev
在 2025/3/15 18:30, Herbert Xu 写道:
> As the acomp interface supports folios, use that instead of mapping
> the data in ubifs.
>
> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
> ---
> fs/ubifs/compress.c | 106 +++++++++++++++++++++++++++++++++++++++++++-
> fs/ubifs/file.c | 74 +++++++++++--------------------
> fs/ubifs/journal.c | 9 ++--
> fs/ubifs/ubifs.h | 11 ++++-
> 4 files changed, 145 insertions(+), 55 deletions(-)
Tested-by: Zhihao Cheng <chengzhihao1@huawei.com> # For xfstests
>
> diff --git a/fs/ubifs/compress.c b/fs/ubifs/compress.c
> index a241ba01c9a8..ea6f06adcd43 100644
> --- a/fs/ubifs/compress.c
> +++ b/fs/ubifs/compress.c
> @@ -16,6 +16,7 @@
> */
>
> #include <crypto/acompress.h>
> +#include <linux/highmem.h>
> #include "ubifs.h"
>
> /* Fake description object for the "none" compressor */
> @@ -126,7 +127,7 @@ void ubifs_compress(const struct ubifs_info *c, const void *in_buf,
> {
> ACOMP_REQUEST_ALLOC(req, compr->cc, GFP_NOFS | __GFP_NOWARN);
>
> - acomp_request_set_src_nondma(req, in_buf, in_len);
> + acomp_request_set_src_dma(req, in_buf, in_len);
Why not merging it into patch 13?
> err = ubifs_compress_req(c, req, out_buf, out_len, compr->name);
> }
>
> @@ -141,6 +142,58 @@ void ubifs_compress(const struct ubifs_info *c, const void *in_buf,
> *compr_type = UBIFS_COMPR_NONE;
> }
>
> +/**
> + * ubifs_compress_folio - compress folio.
> + * @c: UBIFS file-system description object
> + * @in_folio: data to compress
> + * @in_offset: offset into @in_folio
> + * @in_len: length of the data to compress
> + * @out_buf: output buffer where compressed data should be stored
> + * @out_len: output buffer length is returned here
> + * @compr_type: type of compression to use on enter, actually used compression
> + * type on exit
> + *
> + * This function compresses input folio @in_folio of length @in_len and
> + * stores the result in the output buffer @out_buf and the resulting length
> + * in @out_len. If the input buffer does not compress, it is just copied
> + * to the @out_buf. The same happens if @compr_type is %UBIFS_COMPR_NONE
> + * or if compression error occurred.
> + *
> + * Note, if the input buffer was not compressed, it is copied to the output
> + * buffer and %UBIFS_COMPR_NONE is returned in @compr_type.
> + */
> +void ubifs_compress_folio(const struct ubifs_info *c, struct folio *in_folio,
> + size_t in_offset, int in_len, void *out_buf,
> + int *out_len, int *compr_type)
> +{
> + int err;
> + struct ubifs_compressor *compr = ubifs_compressors[*compr_type];
> +
> + if (*compr_type == UBIFS_COMPR_NONE)
> + goto no_compr;
> +
> + /* If the input data is small, do not even try to compress it */
> + if (in_len < UBIFS_MIN_COMPR_LEN)
> + goto no_compr;
> +
> + {
> + ACOMP_REQUEST_ALLOC(req, compr->cc, GFP_NOFS | __GFP_NOWARN);
> +
> + acomp_request_set_src_folio(req, in_folio, in_offset, in_len);
> + err = ubifs_compress_req(c, req, out_buf, out_len, compr->name);
> + }
> +
> + if (err)
> + goto no_compr;
> +
> + return;
> +
> +no_compr:
> + memcpy_from_folio(out_buf, in_folio, in_offset, in_len);
> + *out_len = in_len;
> + *compr_type = UBIFS_COMPR_NONE;
> +}
> +
> static int ubifs_decompress_req(const struct ubifs_info *c,
> struct acomp_req *req,
> const void *in_buf, int in_len, int *out_len,
> @@ -205,7 +258,56 @@ int ubifs_decompress(const struct ubifs_info *c, const void *in_buf,
> {
> ACOMP_REQUEST_ALLOC(req, compr->cc, GFP_NOFS | __GFP_NOWARN);
>
> - acomp_request_set_dst_nondma(req, out_buf, *out_len);
> + acomp_request_set_dst_dma(req, out_buf, *out_len);
Same as the suggestion above.
> + return ubifs_decompress_req(c, req, in_buf, in_len, out_len,
> + compr->name);
> + }
> +}
> +
> +/**
> + * ubifs_decompress_folio - decompress folio.
> + * @c: UBIFS file-system description object
> + * @in_buf: data to decompress
> + * @in_len: length of the data to decompress
> + * @out_folio: output folio where decompressed data should
> + * @out_offset: offset into @out_folio
> + * @out_len: output length is returned here
> + * @compr_type: type of compression
> + *
> + * This function decompresses data from buffer @in_buf into folio
> + * @out_folio. The length of the uncompressed data is returned in
> + * @out_len. This functions returns %0 on success or a negative error
> + * code on failure.
> + */
> +int ubifs_decompress_folio(const struct ubifs_info *c, const void *in_buf,
> + int in_len, struct folio *out_folio,
> + size_t out_offset, int *out_len, int compr_type)
> +{
> + struct ubifs_compressor *compr;
> +
> + if (unlikely(compr_type < 0 || compr_type >= UBIFS_COMPR_TYPES_CNT)) {
> + ubifs_err(c, "invalid compression type %d", compr_type);
> + return -EINVAL;
> + }
> +
> + compr = ubifs_compressors[compr_type];
> +
> + if (unlikely(!compr->capi_name)) {
> + ubifs_err(c, "%s compression is not compiled in", compr->name);
> + return -EINVAL;
> + }
> +
> + if (compr_type == UBIFS_COMPR_NONE) {
> + memcpy_to_folio(out_folio, out_offset, in_buf, in_len);
> + *out_len = in_len;
> + return 0;
> + }
> +
> + {
> + ACOMP_REQUEST_ALLOC(req, compr->cc, GFP_NOFS | __GFP_NOWARN);
> +
> + acomp_request_set_dst_folio(req, out_folio, out_offset,
> + *out_len);
> return ubifs_decompress_req(c, req, in_buf, in_len, out_len,
> compr->name);
> }
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [v5 PATCH 14/14] ubifs: Pass folios to acomp
2025-03-19 9:44 ` Zhihao Cheng
@ 2025-03-19 9:46 ` Herbert Xu
2025-03-19 12:28 ` Zhihao Cheng
0 siblings, 1 reply; 24+ messages in thread
From: Herbert Xu @ 2025-03-19 9:46 UTC (permalink / raw)
To: Zhihao Cheng
Cc: Linux Crypto Mailing List, Richard Weinberger, linux-mtd,
Rafael J. Wysocki, Pavel Machek, linux-pm, Steffen Klassert,
netdev
On Wed, Mar 19, 2025 at 05:44:17PM +0800, Zhihao Cheng wrote:
>
> Tested-by: Zhihao Cheng <chengzhihao1@huawei.com> # For xfstests
Thank you for testing!
> >
> > diff --git a/fs/ubifs/compress.c b/fs/ubifs/compress.c
> > index a241ba01c9a8..ea6f06adcd43 100644
> > --- a/fs/ubifs/compress.c
> > +++ b/fs/ubifs/compress.c
> > @@ -16,6 +16,7 @@
> > */
> > #include <crypto/acompress.h>
> > +#include <linux/highmem.h>
> > #include "ubifs.h"
> > /* Fake description object for the "none" compressor */
> > @@ -126,7 +127,7 @@ void ubifs_compress(const struct ubifs_info *c, const void *in_buf,
> > {
> > ACOMP_REQUEST_ALLOC(req, compr->cc, GFP_NOFS | __GFP_NOWARN);
> > - acomp_request_set_src_nondma(req, in_buf, in_len);
> > + acomp_request_set_src_dma(req, in_buf, in_len);
>
> Why not merging it into patch 13?
Because it will break without this patch. If the input is a highmem
folio it cannot be directly passed over to DMA (because the virtual
address has been remapped by kmap_local).
Cheers,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [v5 PATCH 10/14] crypto: acomp - Add support for folios
2025-03-15 10:30 ` [v5 PATCH 10/14] crypto: acomp - Add support for folios Herbert Xu
@ 2025-03-19 9:57 ` Herbert Xu
0 siblings, 0 replies; 24+ messages in thread
From: Herbert Xu @ 2025-03-19 9:57 UTC (permalink / raw)
To: Linux Crypto Mailing List
Cc: Richard Weinberger, Zhihao Cheng, linux-mtd, Rafael J. Wysocki,
Pavel Machek, linux-pm, Steffen Klassert, netdev
On Sat, Mar 15, 2025 at 06:30:40PM +0800, Herbert Xu wrote:
>
> - n = slen / PAGE_SIZE;
> - n += (offset_in_page(slen) + soff - 1) / PAGE_SIZE;
> - if (slen <= req->src->length &&
> - (!PageHighMem(nth_page(spage, n)) ||
> - size_add(soff, slen) <= PAGE_SIZE))
> + spage = nth_page(spage, soff / PAGE_SIZE);
> + soff = offset_in_page(soff);
> +
> + n = slen / PAGE_SIZE;
> + n += (offset_in_page(slen) + soff - 1) / PAGE_SIZE;
> + if (PageHighMem(nth_page(spage, n)) &&
> + size_add(soff, slen) <= PAGE_SIZE)
> + break;
This should of course be
size_add(soff, slen) > PAGE_SIZE
> + if (PageHighMem(dpage + n) &&
> + size_add(doff, dlen) <= PAGE_SIZE)
Ditto.
Cheers,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [v5 PATCH 14/14] ubifs: Pass folios to acomp
2025-03-19 9:46 ` Herbert Xu
@ 2025-03-19 12:28 ` Zhihao Cheng
0 siblings, 0 replies; 24+ messages in thread
From: Zhihao Cheng @ 2025-03-19 12:28 UTC (permalink / raw)
To: Herbert Xu
Cc: Linux Crypto Mailing List, Richard Weinberger, linux-mtd,
Rafael J. Wysocki, Pavel Machek, linux-pm, Steffen Klassert,
netdev
在 2025/3/19 17:46, Herbert Xu 写道:
> On Wed, Mar 19, 2025 at 05:44:17PM +0800, Zhihao Cheng wrote:
>>
>> Tested-by: Zhihao Cheng <chengzhihao1@huawei.com> # For xfstests
>
> Thank you for testing!
>
>>>
>>> diff --git a/fs/ubifs/compress.c b/fs/ubifs/compress.c
>>> index a241ba01c9a8..ea6f06adcd43 100644
>>> --- a/fs/ubifs/compress.c
>>> +++ b/fs/ubifs/compress.c
>>> @@ -16,6 +16,7 @@
>>> */
>>> #include <crypto/acompress.h>
>>> +#include <linux/highmem.h>
>>> #include "ubifs.h"
>>> /* Fake description object for the "none" compressor */
>>> @@ -126,7 +127,7 @@ void ubifs_compress(const struct ubifs_info *c, const void *in_buf,
>>> {
>>> ACOMP_REQUEST_ALLOC(req, compr->cc, GFP_NOFS | __GFP_NOWARN);
>>> - acomp_request_set_src_nondma(req, in_buf, in_len);
>>> + acomp_request_set_src_dma(req, in_buf, in_len);
>>
>> Why not merging it into patch 13?
>
> Because it will break without this patch. If the input is a highmem
> folio it cannot be directly passed over to DMA (because the virtual
> address has been remapped by kmap_local).
Makes sense.
>
> Cheers,
>
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [v5 PATCH 11/14] xfrm: ipcomp: Use crypto_acomp interface
2025-03-15 10:30 ` [v5 PATCH 11/14] xfrm: ipcomp: Use crypto_acomp interface Herbert Xu
@ 2025-03-20 9:33 ` Herbert Xu
2025-04-25 12:11 ` Sabrina Dubroca
1 sibling, 0 replies; 24+ messages in thread
From: Herbert Xu @ 2025-03-20 9:33 UTC (permalink / raw)
To: Linux Crypto Mailing List
Cc: Richard Weinberger, Zhihao Cheng, linux-mtd, Rafael J. Wysocki,
Pavel Machek, linux-pm, Steffen Klassert, netdev
On Sat, Mar 15, 2025 at 06:30:43PM +0800, Herbert Xu wrote:
>
> + sg_init_table(dsg, dnfrags);
> + total = 0;
> + for (i = 0; i < dnfrags && total < dlen; i++) {
> + struct page *page;
> +
> + page = alloc_page(GFP_ATOMIC);
> + if (!page)
> + break;
> + sg_set_page(dsg + i, page, PAGE_SIZE, 0);
> + total += PAGE_SIZE;
> + }
> + if (!i)
> + return ERR_PTR(-ENOMEM);
> + sg_mark_end(dsg + i - 1);
This is missing a
dlen = min(dlen, total);
> +
> + acomp_request_set_params(req, sg, dsg, plen, dlen);
Cheers,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [v5 PATCH 11/14] xfrm: ipcomp: Use crypto_acomp interface
2025-03-15 10:30 ` [v5 PATCH 11/14] xfrm: ipcomp: Use crypto_acomp interface Herbert Xu
2025-03-20 9:33 ` Herbert Xu
@ 2025-04-25 12:11 ` Sabrina Dubroca
2025-04-25 12:20 ` Herbert Xu
1 sibling, 1 reply; 24+ messages in thread
From: Sabrina Dubroca @ 2025-04-25 12:11 UTC (permalink / raw)
To: Herbert Xu
Cc: Linux Crypto Mailing List, Richard Weinberger, Zhihao Cheng,
linux-mtd, Rafael J. Wysocki, Pavel Machek, linux-pm,
Steffen Klassert, netdev
Hi Herbert,
2025-03-15, 18:30:43 +0800, Herbert Xu wrote:
> +static int ipcomp_post_acomp(struct sk_buff *skb, int err, int hlen)
> +{
> + struct acomp_req *req = ipcomp_cb(skb)->req;
> + struct ipcomp_req_extra *extra;
> + const int plen = skb->data_len;
> + struct scatterlist *dsg;
> + int len, dlen;
>
> - len = dlen - plen;
> - if (len > skb_tailroom(skb))
> - len = skb_tailroom(skb);
> + if (unlikely(err))
> + goto out_free_req;
>
> - __skb_put(skb, len);
> + extra = acomp_request_extra(req);
> + dsg = extra->sg;
> + dlen = req->dlen;
>
> - len += plen;
> - skb_copy_to_linear_data(skb, scratch, len);
> + pskb_trim_unique(skb, 0);
> + __skb_put(skb, hlen);
>
> - while ((scratch += len, dlen -= len) > 0) {
> + /* Only update truesize on input. */
> + if (!hlen)
> + skb->truesize += dlen - plen;
Are you sure we need to subtract plen here? When I run fragmented
traffic with ipcomp, I'm hitting the WARN from skb_try_coalesce during
reassembly, ie truesize is too small:
delta = from->truesize - SKB_TRUESIZE(skb_end_offset(from));
WARN_ON_ONCE(delta < len);
The splat goes away with
/* Only update truesize on input. */
if (!hlen)
- skb->truesize += dlen - plen;
+ skb->truesize += dlen;
skb->data_len = dlen;
skb->len += dlen;
pskb_trim_unique ends up calling skb_condense, which seems to adjust
the truesize to account for all frags being dropped.
Does that look like the right fix to you?
--
Sabrina
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [v5 PATCH 11/14] xfrm: ipcomp: Use crypto_acomp interface
2025-04-25 12:11 ` Sabrina Dubroca
@ 2025-04-25 12:20 ` Herbert Xu
2025-04-25 12:28 ` Sabrina Dubroca
0 siblings, 1 reply; 24+ messages in thread
From: Herbert Xu @ 2025-04-25 12:20 UTC (permalink / raw)
To: Sabrina Dubroca
Cc: Linux Crypto Mailing List, Richard Weinberger, Zhihao Cheng,
linux-mtd, Rafael J. Wysocki, Pavel Machek, linux-pm,
Steffen Klassert, netdev
On Fri, Apr 25, 2025 at 02:11:44PM +0200, Sabrina Dubroca wrote:
>
> The splat goes away with
>
> /* Only update truesize on input. */
> if (!hlen)
> - skb->truesize += dlen - plen;
> + skb->truesize += dlen;
> skb->data_len = dlen;
> skb->len += dlen;
>
> pskb_trim_unique ends up calling skb_condense, which seems to adjust
> the truesize to account for all frags being dropped.
>
> Does that look like the right fix to you?
You're right. I must've missed the truesize update in skb_condense
when writing this.
Thanks,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [v5 PATCH 11/14] xfrm: ipcomp: Use crypto_acomp interface
2025-04-25 12:20 ` Herbert Xu
@ 2025-04-25 12:28 ` Sabrina Dubroca
0 siblings, 0 replies; 24+ messages in thread
From: Sabrina Dubroca @ 2025-04-25 12:28 UTC (permalink / raw)
To: Herbert Xu
Cc: Linux Crypto Mailing List, Richard Weinberger, Zhihao Cheng,
linux-mtd, Rafael J. Wysocki, Pavel Machek, linux-pm,
Steffen Klassert, netdev
2025-04-25, 20:20:42 +0800, Herbert Xu wrote:
> On Fri, Apr 25, 2025 at 02:11:44PM +0200, Sabrina Dubroca wrote:
> >
> > The splat goes away with
> >
> > /* Only update truesize on input. */
> > if (!hlen)
> > - skb->truesize += dlen - plen;
> > + skb->truesize += dlen;
> > skb->data_len = dlen;
> > skb->len += dlen;
> >
> > pskb_trim_unique ends up calling skb_condense, which seems to adjust
> > the truesize to account for all frags being dropped.
> >
> > Does that look like the right fix to you?
>
> You're right. I must've missed the truesize update in skb_condense
> when writing this.
Ok, I'll submit the patch in a bit. Thanks.
--
Sabrina
^ permalink raw reply [flat|nested] 24+ messages in thread
end of thread, other threads:[~2025-04-25 12:28 UTC | newest]
Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-03-15 10:30 [v5 PATCH 00/14] crypto: acomp - Add virtual address and folio support Herbert Xu
2025-03-15 10:30 ` [v5 PATCH 01/14] xfrm: ipcomp: Call pskb_may_pull in ipcomp_input Herbert Xu
2025-03-15 10:30 ` [v5 PATCH 02/14] crypto: scomp - Remove support for some non-trivial SG lists Herbert Xu
2025-03-15 10:30 ` [v5 PATCH 03/14] crypto: iaa - Remove dst_null support Herbert Xu
2025-03-15 10:30 ` [v5 PATCH 04/14] crypto: qat " Herbert Xu
2025-03-15 10:30 ` [v5 PATCH 05/14] crypto: acomp - Remove dst_free Herbert Xu
2025-03-15 10:30 ` [v5 PATCH 06/14] crypto: scomp - Add chaining and virtual address support Herbert Xu
2025-03-15 10:30 ` [v5 PATCH 07/14] crypto: acomp - Add ACOMP_REQUEST_ALLOC and acomp_request_alloc_extra Herbert Xu
2025-03-15 10:30 ` [v5 PATCH 08/14] crypto: iaa - Use acomp stack fallback Herbert Xu
2025-03-15 10:30 ` [v5 PATCH 09/14] crypto: acomp - Add async nondma fallback Herbert Xu
2025-03-15 10:30 ` [v5 PATCH 10/14] crypto: acomp - Add support for folios Herbert Xu
2025-03-19 9:57 ` Herbert Xu
2025-03-15 10:30 ` [v5 PATCH 11/14] xfrm: ipcomp: Use crypto_acomp interface Herbert Xu
2025-03-20 9:33 ` Herbert Xu
2025-04-25 12:11 ` Sabrina Dubroca
2025-04-25 12:20 ` Herbert Xu
2025-04-25 12:28 ` Sabrina Dubroca
2025-03-15 10:30 ` [v5 PATCH 12/14] PM: hibernate: " Herbert Xu
2025-03-15 10:30 ` [v5 PATCH 13/14] ubifs: " Herbert Xu
2025-03-19 9:39 ` Zhihao Cheng
2025-03-15 10:30 ` [v5 PATCH 14/14] ubifs: Pass folios to acomp Herbert Xu
2025-03-19 9:44 ` Zhihao Cheng
2025-03-19 9:46 ` Herbert Xu
2025-03-19 12:28 ` Zhihao Cheng
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).