* [PATCH v2 0/5] crypto: iaa - Fixes for multi entry SG lists
@ 2026-08-05 21:19 Vinicius Costa Gomes
2026-08-05 21:19 ` [PATCH v2 1/5] dmaengine: idxd: assign all engines to group 0 in IAA defaults Vinicius Costa Gomes
` (4 more replies)
0 siblings, 5 replies; 10+ messages in thread
From: Vinicius Costa Gomes @ 2026-08-05 21:19 UTC (permalink / raw)
To: Dave Jiang, Vinod Koul, Frank Li, Kristen Accardi, Herbert Xu,
David S. Miller, Andrew Morton, Yosry Ahmed, Nhat Pham
Cc: dmaengine, linux-kernel, linux-crypto, Vinicius Costa Gomes,
Giovanni Cabiddu, stable
Since commit e2c3b6b21c77 ("mm: zswap: use SG list decompression APIs
from zsmalloc"), iaa_crypto started seeing some failures with
multi-entry scatter lists.
For that we introduce software fallback, in patch 2/5, to iaa-crypto
when SG lists have more than one entry, for both input and output.
Patch 4/5 adds a bounce buffer so small/simple requests can be
linearized and sent to the hardware. This recovers most of the
performance.
Patch 1/5 updates the default resources reserved to iaa-crypto so more
engines are associated to the iaa_crypto group, resulting in better
utilization by default. Patch 3/5 fixes so software request "bytes"
are not counted as hardware "bytes". As the idxd changes only affect
iaa_crypto, sending them here makes more sense. Patch 5/5 fixes a
pre-existing issue pointed out by sashiko, that could cause data
corruption when a hardware error is reported.
A potential use-after-free issue when a descriptor submission times
out, pointed out by Sashiko, still remains and will be handled on a
future series.
It should be noted that as the software and hardware implementations
have different expectations for the window size, something like patch
[1] or the future 'set_params()' API are needed to verify that patch
2/5 works without patch 4/5.
[1] https://lore.kernel.org/linux-crypto/20260326100433.57324-1-giovanni.cabiddu@intel.com/
Cheers,
Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
---
Changes in v2:
- Added patch 5/5, for a pre-existing issue, that touches the same
code paths as this series (Sashiko);
- I took an old version of Giovanni's patch 4/5, new version is
simpler to read; because of changes did not take Dave Jiang's
Reviewed-by;
- Added the missing Signed-off-by tags (Dave Jiang);
- Link to v1: https://patch.msgid.link/20260713-iaa-crypto-fixes-zswap-v1-0-65cac23c684d@intel.com
---
Giovanni Cabiddu (4):
dmaengine: idxd: assign all engines to group 0 in IAA defaults
crypto: iaa - fall back to software for multi-entry scatterlists
crypto: iaa - avoid counting fallback decompression bytes
crypto: iaa - use bounce buffer for multi-sg decompress input
Vinicius Costa Gomes (1):
crypto: iaa - unmap dst before software fallback on decompress
drivers/crypto/intel/iaa/iaa_crypto_main.c | 270 +++++++++++++++++++---------
drivers/crypto/intel/iaa/iaa_crypto_stats.c | 9 +
drivers/crypto/intel/iaa/iaa_crypto_stats.h | 2 +
drivers/dma/idxd/defaults.c | 12 +-
4 files changed, 201 insertions(+), 92 deletions(-)
---
base-commit: 947d62c094367ef6064907d570b47612cd579df6
change-id: 20260713-iaa-crypto-fixes-zswap-ff5baae311d1
Best regards,
--
Vinicius
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2 1/5] dmaengine: idxd: assign all engines to group 0 in IAA defaults
2026-08-05 21:19 [PATCH v2 0/5] crypto: iaa - Fixes for multi entry SG lists Vinicius Costa Gomes
@ 2026-08-05 21:19 ` Vinicius Costa Gomes
2026-08-05 21:41 ` sashiko-bot
2026-08-05 21:19 ` [PATCH v2 2/5] crypto: iaa - fall back to software for multi-entry scatterlists Vinicius Costa Gomes
` (3 subsequent siblings)
4 siblings, 1 reply; 10+ messages in thread
From: Vinicius Costa Gomes @ 2026-08-05 21:19 UTC (permalink / raw)
To: Dave Jiang, Vinod Koul, Frank Li, Kristen Accardi, Herbert Xu,
David S. Miller, Andrew Morton, Yosry Ahmed, Nhat Pham
Cc: dmaengine, linux-kernel, linux-crypto, Vinicius Costa Gomes,
Giovanni Cabiddu
From: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
The IAA device defaults only assigned engine 0 to group 0, leaving
engines 1 through max_engines-1 unassigned (group_id = -1). This means
that by default only a single engine processed descriptors, limiting
throughput to one engine's capacity.
Assign all available engines to group 0 so that the full hardware
parallelism is used out of the box without requiring manual
accel-config setup.
Signed-off-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
---
drivers/dma/idxd/defaults.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/drivers/dma/idxd/defaults.c b/drivers/dma/idxd/defaults.c
index 2bbbcd02a0da..26ebfa2ca144 100644
--- a/drivers/dma/idxd/defaults.c
+++ b/drivers/dma/idxd/defaults.c
@@ -8,6 +8,7 @@ int idxd_load_iaa_device_defaults(struct idxd_device *idxd)
struct idxd_engine *engine;
struct idxd_group *group;
struct idxd_wq *wq;
+ int i;
if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
return 0;
@@ -41,11 +42,12 @@ int idxd_load_iaa_device_defaults(struct idxd_device *idxd)
/* set driver_name to "crypto" */
strscpy_pad(wq->driver_name, "crypto");
- engine = idxd->engines[0];
-
- /* set engine group to 0 */
- engine->group = idxd->groups[0];
- engine->group->num_engines++;
+ /* assign all engines to group 0 */
+ for (i = 0; i < idxd->max_engines; i++) {
+ engine = idxd->engines[i];
+ engine->group = group;
+ group->num_engines++;
+ }
return 0;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v2 2/5] crypto: iaa - fall back to software for multi-entry scatterlists
2026-08-05 21:19 [PATCH v2 0/5] crypto: iaa - Fixes for multi entry SG lists Vinicius Costa Gomes
2026-08-05 21:19 ` [PATCH v2 1/5] dmaengine: idxd: assign all engines to group 0 in IAA defaults Vinicius Costa Gomes
@ 2026-08-05 21:19 ` Vinicius Costa Gomes
2026-08-05 21:38 ` sashiko-bot
2026-08-05 21:19 ` [PATCH v2 3/5] crypto: iaa - avoid counting fallback decompression bytes Vinicius Costa Gomes
` (2 subsequent siblings)
4 siblings, 1 reply; 10+ messages in thread
From: Vinicius Costa Gomes @ 2026-08-05 21:19 UTC (permalink / raw)
To: Dave Jiang, Vinod Koul, Frank Li, Kristen Accardi, Herbert Xu,
David S. Miller, Andrew Morton, Yosry Ahmed, Nhat Pham
Cc: dmaengine, linux-kernel, linux-crypto, Vinicius Costa Gomes,
Giovanni Cabiddu, stable
From: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
IAA cannot process source or destination scatterlists with more than one
entry directly. Instead of failing these requests, route them through a
separate deflate acomp transform and keep the request alive in software.
The IAA driver has never handled multi-entry scatterlists, but the
limitation was latent until commit e2c3b6b21c77 ("mm: zswap: use SG list
decompression APIs from zsmalloc") made zswap pass the raw zsmalloc SG
list directly to crypto drivers, so objects spanning multiple pages now
reach IAA as multi-entry sources and would otherwise fail decompression.
Fallback to the generic DEFLATE implementation for scatterlists with
more than one entry. After the multi-entry cases fall back early,
simplify the DMA mapping path to a single scatterlist entry and fall
back on mapping failure as well.
Add counters to track the number of requests processed by the software
implementation on the compression direction.
Fixes: 2ec6761df889 ("crypto: iaa - Add support for deflate-iaa compression algorithm")
Fixes: e2c3b6b21c77 ("mm: zswap: use SG list decompression APIs from zsmalloc")
Cc: stable@vger.kernel.org
Signed-off-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
---
drivers/crypto/intel/iaa/iaa_crypto_main.c | 111 +++++++++++++++-------------
drivers/crypto/intel/iaa/iaa_crypto_stats.c | 9 +++
drivers/crypto/intel/iaa/iaa_crypto_stats.h | 2 +
3 files changed, 71 insertions(+), 51 deletions(-)
diff --git a/drivers/crypto/intel/iaa/iaa_crypto_main.c b/drivers/crypto/intel/iaa/iaa_crypto_main.c
index f62b994e18e5..904d9413ba18 100644
--- a/drivers/crypto/intel/iaa/iaa_crypto_main.c
+++ b/drivers/crypto/intel/iaa/iaa_crypto_main.c
@@ -2,6 +2,7 @@
/* Copyright(c) 2021 Intel Corporation. All rights rsvd. */
#include <linux/init.h>
+#include <linux/crypto.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -996,6 +997,19 @@ static int deflate_generic_decompress(struct acomp_req *req)
return ret;
}
+static int deflate_generic_compress(struct acomp_req *req)
+{
+ ACOMP_FBREQ_ON_STACK(fbreq, req);
+ int ret;
+
+ ret = crypto_acomp_compress(fbreq);
+ req->dlen = fbreq->dlen;
+
+ update_total_sw_comp_calls();
+
+ return ret;
+}
+
static int iaa_remap_for_verify(struct device *dev, struct iaa_wq *iaa_wq,
struct acomp_req *req,
dma_addr_t *src_addr, dma_addr_t *dst_addr);
@@ -1472,7 +1486,7 @@ 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;
- int nr_sgs, cpu, ret = 0;
+ int cpu, ret = 0;
struct iaa_wq *iaa_wq;
struct idxd_wq *wq;
struct device *dev;
@@ -1484,11 +1498,15 @@ static int iaa_comp_acompress(struct acomp_req *req)
return -ENODEV;
}
- if (!req->src || !req->slen) {
- pr_debug("invalid src, not compressing\n");
+ if (!req->src || !req->slen || !req->dst) {
+ pr_debug("invalid req, not compressing\n");
return -EINVAL;
}
+ /* Fall back to software if src or dst has multiple sg entries */
+ if (sg_nents(req->src) > 1 || sg_nents(req->dst) > 1)
+ return deflate_generic_compress(req);
+
cpu = get_cpu();
wq = wq_table_next_wq(cpu);
put_cpu();
@@ -1507,30 +1525,25 @@ static int iaa_comp_acompress(struct acomp_req *req)
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;
+ if (!dma_map_sg(dev, req->src, 1, DMA_TO_DEVICE)) {
+ dev_dbg(dev, "couldn't map src sg for iaa device %d, wq %d\n",
+ iaa_wq->iaa_device->idxd->id, iaa_wq->wq->id);
+ iaa_wq_put(wq);
+ return deflate_generic_compress(req);
}
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,
+ dev_dbg(dev, "map src %llx req->src %p slen %d sg_len %d\n", src_addr,
req->src, req->slen, sg_dma_len(req->src));
- 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;
+ if (!dma_map_sg(dev, req->dst, 1, DMA_FROM_DEVICE)) {
+ dev_dbg(dev, "couldn't map dst sg for iaa device %d, wq %d\n",
+ iaa_wq->iaa_device->idxd->id, iaa_wq->wq->id);
+ dma_unmap_sg(dev, req->src, 1, DMA_TO_DEVICE);
+ iaa_wq_put(wq);
+ return deflate_generic_compress(req);
}
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,
+ dev_dbg(dev, "map dst %llx req->dst %p dlen %d sg_len %d\n", dst_addr,
req->dst, req->dlen, sg_dma_len(req->dst));
ret = iaa_compress(tfm, req, wq, src_addr, req->slen, dst_addr,
@@ -1550,8 +1563,8 @@ static int iaa_comp_acompress(struct acomp_req *req)
if (ret)
dev_dbg(dev, "asynchronous compress verification failed ret=%d\n", ret);
- dma_unmap_sg(dev, req->dst, sg_nents(req->dst), DMA_TO_DEVICE);
- dma_unmap_sg(dev, req->src, sg_nents(req->src), DMA_FROM_DEVICE);
+ dma_unmap_sg(dev, req->dst, 1, DMA_TO_DEVICE);
+ dma_unmap_sg(dev, req->src, 1, DMA_FROM_DEVICE);
goto out;
}
@@ -1559,9 +1572,8 @@ static int iaa_comp_acompress(struct acomp_req *req)
if (ret)
dev_dbg(dev, "asynchronous compress 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);
+ dma_unmap_sg(dev, req->dst, 1, DMA_FROM_DEVICE);
+ dma_unmap_sg(dev, req->src, 1, DMA_TO_DEVICE);
out:
iaa_wq_put(wq);
@@ -1572,7 +1584,7 @@ static int iaa_comp_adecompress(struct acomp_req *req)
{
struct crypto_tfm *tfm = req->base.tfm;
dma_addr_t src_addr, dst_addr;
- int nr_sgs, cpu, ret = 0;
+ int cpu, ret = 0;
struct iaa_wq *iaa_wq;
struct device *dev;
struct idxd_wq *wq;
@@ -1582,11 +1594,15 @@ static int iaa_comp_adecompress(struct acomp_req *req)
return -ENODEV;
}
- if (!req->src || !req->slen) {
- pr_debug("invalid src, not decompressing\n");
+ if (!req->src || !req->slen || !req->dst) {
+ pr_debug("invalid req, not decompressing\n");
return -EINVAL;
}
+ /* Fall back to software if src or dst has multiple sg entries */
+ if (sg_nents(req->src) > 1 || sg_nents(req->dst) > 1)
+ return deflate_generic_decompress(req);
+
cpu = get_cpu();
wq = wq_table_next_wq(cpu);
put_cpu();
@@ -1605,30 +1621,25 @@ static int iaa_comp_adecompress(struct acomp_req *req)
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;
+ if (!dma_map_sg(dev, req->src, 1, DMA_TO_DEVICE)) {
+ dev_dbg(dev, "couldn't map src sg for iaa device %d, wq %d\n",
+ iaa_wq->iaa_device->idxd->id, iaa_wq->wq->id);
+ iaa_wq_put(wq);
+ return deflate_generic_decompress(req);
}
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,
+ dev_dbg(dev, "map src %llx req->src %p slen %d sg_len %d\n", src_addr,
req->src, req->slen, sg_dma_len(req->src));
- 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;
+ if (!dma_map_sg(dev, req->dst, 1, DMA_FROM_DEVICE)) {
+ dev_dbg(dev, "couldn't map dst sg for iaa device %d, wq %d\n",
+ iaa_wq->iaa_device->idxd->id, iaa_wq->wq->id);
+ dma_unmap_sg(dev, req->src, 1, DMA_TO_DEVICE);
+ iaa_wq_put(wq);
+ return deflate_generic_decompress(req);
}
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,
+ dev_dbg(dev, "map dst %llx req->dst %p dlen %d sg_len %d\n", dst_addr,
req->dst, req->dlen, sg_dma_len(req->dst));
ret = iaa_decompress(tfm, req, wq, src_addr, req->slen,
@@ -1639,10 +1650,8 @@ static int iaa_comp_adecompress(struct acomp_req *req)
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:
+ dma_unmap_sg(dev, req->dst, 1, DMA_FROM_DEVICE);
+ dma_unmap_sg(dev, req->src, 1, DMA_TO_DEVICE);
iaa_wq_put(wq);
return ret;
diff --git a/drivers/crypto/intel/iaa/iaa_crypto_stats.c b/drivers/crypto/intel/iaa/iaa_crypto_stats.c
index f5cc3d29ca19..2f2ed88c8812 100644
--- a/drivers/crypto/intel/iaa/iaa_crypto_stats.c
+++ b/drivers/crypto/intel/iaa/iaa_crypto_stats.c
@@ -19,6 +19,7 @@
static atomic64_t total_comp_calls;
static atomic64_t total_decomp_calls;
+static atomic64_t total_sw_comp_calls;
static atomic64_t total_sw_decomp_calls;
static atomic64_t total_comp_bytes_out;
static atomic64_t total_decomp_bytes_in;
@@ -43,6 +44,11 @@ void update_total_decomp_calls(void)
atomic64_inc(&total_decomp_calls);
}
+void update_total_sw_comp_calls(void)
+{
+ atomic64_inc(&total_sw_comp_calls);
+}
+
void update_total_sw_decomp_calls(void)
{
atomic64_inc(&total_sw_decomp_calls);
@@ -104,6 +110,7 @@ static void reset_iaa_crypto_stats(void)
{
atomic64_set(&total_comp_calls, 0);
atomic64_set(&total_decomp_calls, 0);
+ atomic64_set(&total_sw_comp_calls, 0);
atomic64_set(&total_sw_decomp_calls, 0);
atomic64_set(&total_comp_bytes_out, 0);
atomic64_set(&total_decomp_bytes_in, 0);
@@ -174,6 +181,8 @@ static int global_stats_show(struct seq_file *m, void *v)
atomic64_read(&total_comp_calls));
seq_printf(m, " total_decomp_calls: %llu\n",
atomic64_read(&total_decomp_calls));
+ seq_printf(m, " total_sw_comp_calls: %llu\n",
+ atomic64_read(&total_sw_comp_calls));
seq_printf(m, " total_sw_decomp_calls: %llu\n",
atomic64_read(&total_sw_decomp_calls));
seq_printf(m, " total_comp_bytes_out: %llu\n",
diff --git a/drivers/crypto/intel/iaa/iaa_crypto_stats.h b/drivers/crypto/intel/iaa/iaa_crypto_stats.h
index 3787a5f507eb..6e0c6f9939bf 100644
--- a/drivers/crypto/intel/iaa/iaa_crypto_stats.h
+++ b/drivers/crypto/intel/iaa/iaa_crypto_stats.h
@@ -11,6 +11,7 @@ void iaa_crypto_debugfs_cleanup(void);
void update_total_comp_calls(void);
void update_total_comp_bytes_out(int n);
void update_total_decomp_calls(void);
+void update_total_sw_comp_calls(void);
void update_total_sw_decomp_calls(void);
void update_total_decomp_bytes_in(int n);
void update_completion_einval_errs(void);
@@ -29,6 +30,7 @@ static inline void iaa_crypto_debugfs_cleanup(void) {}
static inline void update_total_comp_calls(void) {}
static inline void update_total_comp_bytes_out(int n) {}
static inline void update_total_decomp_calls(void) {}
+static inline void update_total_sw_comp_calls(void) {}
static inline void update_total_sw_decomp_calls(void) {}
static inline void update_total_decomp_bytes_in(int n) {}
static inline void update_completion_einval_errs(void) {}
--
2.55.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v2 3/5] crypto: iaa - avoid counting fallback decompression bytes
2026-08-05 21:19 [PATCH v2 0/5] crypto: iaa - Fixes for multi entry SG lists Vinicius Costa Gomes
2026-08-05 21:19 ` [PATCH v2 1/5] dmaengine: idxd: assign all engines to group 0 in IAA defaults Vinicius Costa Gomes
2026-08-05 21:19 ` [PATCH v2 2/5] crypto: iaa - fall back to software for multi-entry scatterlists Vinicius Costa Gomes
@ 2026-08-05 21:19 ` Vinicius Costa Gomes
2026-08-05 21:32 ` sashiko-bot
2026-08-05 21:19 ` [PATCH v2 4/5] crypto: iaa - use bounce buffer for multi-sg decompress input Vinicius Costa Gomes
2026-08-05 21:19 ` [PATCH v2 5/5] crypto: iaa - unmap dst before software fallback on decompress Vinicius Costa Gomes
4 siblings, 1 reply; 10+ messages in thread
From: Vinicius Costa Gomes @ 2026-08-05 21:19 UTC (permalink / raw)
To: Dave Jiang, Vinod Koul, Frank Li, Kristen Accardi, Herbert Xu,
David S. Miller, Andrew Morton, Yosry Ahmed, Nhat Pham
Cc: dmaengine, linux-kernel, linux-crypto, Vinicius Costa Gomes,
Giovanni Cabiddu
From: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
When decompression falls back to deflate-generic after an analytics
error, the request no longer completes through IAA.
Move decompression byte accounting into the successful IAA completion
path in both the synchronous and asynchronous flows so decomp_bytes only
reflects bytes actually processed by IAA.
Signed-off-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
---
drivers/crypto/intel/iaa/iaa_crypto_main.c | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/drivers/crypto/intel/iaa/iaa_crypto_main.c b/drivers/crypto/intel/iaa/iaa_crypto_main.c
index 904d9413ba18..9505ca23e6f3 100644
--- a/drivers/crypto/intel/iaa/iaa_crypto_main.c
+++ b/drivers/crypto/intel/iaa/iaa_crypto_main.c
@@ -1071,15 +1071,17 @@ static void iaa_desc_complete(struct idxd_desc *idxd_desc,
}
} else {
ctx->req->dlen = idxd_desc->iax_completion->output_size;
+
+ if (!ctx->compress) {
+ update_total_decomp_bytes_in(ctx->req->slen);
+ update_wq_decomp_bytes(iaa_wq->wq, ctx->req->slen);
+ }
}
/* Update stats */
if (ctx->compress) {
update_total_comp_bytes_out(ctx->req->dlen);
update_wq_comp_bytes(iaa_wq->wq, ctx->req->dlen);
- } else {
- update_total_decomp_bytes_in(ctx->req->slen);
- update_wq_decomp_bytes(iaa_wq->wq, ctx->req->slen);
}
if (ctx->compress && compression_ctx->verify_compress) {
@@ -1462,16 +1464,16 @@ static int iaa_decompress(struct crypto_tfm *tfm, struct acomp_req *req,
}
} else {
req->dlen = idxd_desc->iax_completion->output_size;
+
+ /* Update stats */
+ update_total_decomp_bytes_in(slen);
+ update_wq_decomp_bytes(wq, slen);
}
*dlen = req->dlen;
if (!ctx->async_mode)
idxd_free_desc(wq, idxd_desc);
-
- /* Update stats */
- update_total_decomp_bytes_in(slen);
- update_wq_decomp_bytes(wq, slen);
out:
return ret;
err:
--
2.55.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v2 4/5] crypto: iaa - use bounce buffer for multi-sg decompress input
2026-08-05 21:19 [PATCH v2 0/5] crypto: iaa - Fixes for multi entry SG lists Vinicius Costa Gomes
` (2 preceding siblings ...)
2026-08-05 21:19 ` [PATCH v2 3/5] crypto: iaa - avoid counting fallback decompression bytes Vinicius Costa Gomes
@ 2026-08-05 21:19 ` Vinicius Costa Gomes
2026-08-05 21:36 ` sashiko-bot
2026-08-05 21:19 ` [PATCH v2 5/5] crypto: iaa - unmap dst before software fallback on decompress Vinicius Costa Gomes
4 siblings, 1 reply; 10+ messages in thread
From: Vinicius Costa Gomes @ 2026-08-05 21:19 UTC (permalink / raw)
To: Dave Jiang, Vinod Koul, Frank Li, Kristen Accardi, Herbert Xu,
David S. Miller, Andrew Morton, Yosry Ahmed, Nhat Pham
Cc: dmaengine, linux-kernel, linux-crypto, Vinicius Costa Gomes,
Giovanni Cabiddu
From: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
Since commit e2c3b6b21c77 ("mm: zswap: use SG list decompression APIs
from zsmalloc"), zswap passes the raw zsmalloc SG list directly to
crypto drivers, so a compressed object spanning multiple pages reaches
IAA as a multi-entry source. Such requests currently fall back to
software decompression.
As IAA hardware requires a single DMA source buffer, linearize small
multi-entry sources into a pre-allocated bounce page and submit that to
the hardware instead of falling back to software. Keep the software
fallback only for multi-entry destinations. This recovers most of the
performance lost by using the software fallback.
Store the bounce-page state in the acomp request context alongside the
existing compression CRC, free it through a shared source-unmap helper,
and back the pages with a small module-wide mempool so the path remains
available in reclaim-driven callers.
Signed-off-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
---
drivers/crypto/intel/iaa/iaa_crypto_main.c | 128 ++++++++++++++++++++++++-----
1 file changed, 106 insertions(+), 22 deletions(-)
diff --git a/drivers/crypto/intel/iaa/iaa_crypto_main.c b/drivers/crypto/intel/iaa/iaa_crypto_main.c
index 9505ca23e6f3..51547c5fcf70 100644
--- a/drivers/crypto/intel/iaa/iaa_crypto_main.c
+++ b/drivers/crypto/intel/iaa/iaa_crypto_main.c
@@ -9,6 +9,7 @@
#include <linux/sysfs.h>
#include <linux/device.h>
#include <linux/iommu.h>
+#include <linux/mempool.h>
#include <uapi/linux/idxd.h>
#include <linux/highmem.h>
#include <linux/sched/smt.h>
@@ -157,6 +158,16 @@ static bool async_mode;
/* Use interrupts */
static bool use_irq;
+struct iaa_req_ctx {
+ u32 compression_crc;
+ struct page *bounce_src;
+ dma_addr_t bounce_src_dma;
+ unsigned int bounce_src_len;
+};
+
+static mempool_t *iaa_bounce_pool;
+#define IAA_BOUNCE_POOL_SIZE 128
+
/**
* set_iaa_sync_mode - Set IAA sync mode
* @name: The name of the sync mode
@@ -984,6 +995,23 @@ static inline int check_completion(struct device *dev,
return ret;
}
+static void iaa_unmap_src(struct device *dev, struct acomp_req *req)
+{
+ struct iaa_req_ctx *req_ctx = acomp_request_ctx(req);
+
+ if (req_ctx->bounce_src) {
+ dma_unmap_page(dev, req_ctx->bounce_src_dma,
+ req_ctx->bounce_src_len, DMA_TO_DEVICE);
+ mempool_free(req_ctx->bounce_src, iaa_bounce_pool);
+ req_ctx->bounce_src = NULL;
+ req_ctx->bounce_src_dma = 0;
+ req_ctx->bounce_src_len = 0;
+ return;
+ }
+
+ dma_unmap_sg(dev, req->src, 1, DMA_TO_DEVICE);
+}
+
static int deflate_generic_decompress(struct acomp_req *req)
{
ACOMP_FBREQ_ON_STACK(fbreq, req);
@@ -1027,6 +1055,7 @@ static void iaa_desc_complete(struct idxd_desc *idxd_desc,
struct iaa_device_compression_mode *active_compression_mode;
struct iaa_compression_ctx *compression_ctx;
struct crypto_ctx *ctx = __ctx;
+ struct iaa_req_ctx *req_ctx = acomp_request_ctx(ctx->req);
struct iaa_device *iaa_device;
struct idxd_device *idxd;
struct iaa_wq *iaa_wq;
@@ -1085,10 +1114,9 @@ static void iaa_desc_complete(struct idxd_desc *idxd_desc,
}
if (ctx->compress && compression_ctx->verify_compress) {
- u32 *compression_crc = acomp_request_ctx(ctx->req);
dma_addr_t src_addr, dst_addr;
- *compression_crc = idxd_desc->iax_completion->crc;
+ req_ctx->compression_crc = idxd_desc->iax_completion->crc;
ret = iaa_remap_for_verify(dev, iaa_wq, ctx->req, &src_addr, &dst_addr);
if (ret) {
@@ -1111,7 +1139,7 @@ static void iaa_desc_complete(struct idxd_desc *idxd_desc,
}
err:
dma_unmap_sg(dev, ctx->req->dst, sg_nents(ctx->req->dst), DMA_FROM_DEVICE);
- dma_unmap_sg(dev, ctx->req->src, sg_nents(ctx->req->src), DMA_TO_DEVICE);
+ iaa_unmap_src(dev, ctx->req);
out:
if (ret != 0)
dev_dbg(dev, "asynchronous compress failed ret=%d\n", ret);
@@ -1131,7 +1159,7 @@ static int iaa_compress(struct crypto_tfm *tfm, struct acomp_req *req,
{
struct iaa_device_compression_mode *active_compression_mode;
struct iaa_compression_ctx *ctx = crypto_tfm_ctx(tfm);
- u32 *compression_crc = acomp_request_ctx(req);
+ struct iaa_req_ctx *req_ctx = acomp_request_ctx(req);
struct iaa_device *iaa_device;
struct idxd_desc *idxd_desc;
struct iax_hw_desc *desc;
@@ -1222,7 +1250,7 @@ static int iaa_compress(struct crypto_tfm *tfm, struct acomp_req *req,
update_total_comp_bytes_out(*dlen);
update_wq_comp_bytes(wq, *dlen);
- *compression_crc = idxd_desc->iax_completion->crc;
+ req_ctx->compression_crc = idxd_desc->iax_completion->crc;
if (!ctx->async_mode)
idxd_free_desc(wq, idxd_desc);
@@ -1282,7 +1310,7 @@ static int iaa_compress_verify(struct crypto_tfm *tfm, struct acomp_req *req,
{
struct iaa_device_compression_mode *active_compression_mode;
struct iaa_compression_ctx *ctx = crypto_tfm_ctx(tfm);
- u32 *compression_crc = acomp_request_ctx(req);
+ struct iaa_req_ctx *req_ctx = acomp_request_ctx(req);
struct iaa_device *iaa_device;
struct idxd_desc *idxd_desc;
struct iax_hw_desc *desc;
@@ -1342,10 +1370,10 @@ static int iaa_compress_verify(struct crypto_tfm *tfm, struct acomp_req *req,
goto err;
}
- if (*compression_crc != idxd_desc->iax_completion->crc) {
+ if (req_ctx->compression_crc != idxd_desc->iax_completion->crc) {
ret = -EINVAL;
- dev_dbg(dev, "(verify) iaa comp/decomp crc mismatch:"
- " comp=0x%x, decomp=0x%x\n", *compression_crc,
+ dev_dbg(dev, "(verify) iaa comp/decomp crc mismatch: comp=0x%x, decomp=0x%x\n",
+ req_ctx->compression_crc,
idxd_desc->iax_completion->crc);
print_hex_dump(KERN_INFO, "cmp-rec: ", DUMP_PREFIX_OFFSET,
8, 1, idxd_desc->iax_completion, 64, 0);
@@ -1485,6 +1513,7 @@ static int iaa_decompress(struct crypto_tfm *tfm, struct acomp_req *req,
static int iaa_comp_acompress(struct acomp_req *req)
{
+ struct iaa_req_ctx *req_ctx = acomp_request_ctx(req);
struct iaa_compression_ctx *compression_ctx;
struct crypto_tfm *tfm = req->base.tfm;
dma_addr_t src_addr, dst_addr;
@@ -1493,6 +1522,10 @@ static int iaa_comp_acompress(struct acomp_req *req)
struct idxd_wq *wq;
struct device *dev;
+ req_ctx->bounce_src = NULL;
+ req_ctx->bounce_src_dma = 0;
+ req_ctx->bounce_src_len = 0;
+
compression_ctx = crypto_tfm_ctx(tfm);
if (!iaa_crypto_enabled) {
@@ -1584,12 +1617,19 @@ static int iaa_comp_acompress(struct acomp_req *req)
static int iaa_comp_adecompress(struct acomp_req *req)
{
+ struct iaa_req_ctx *req_ctx = acomp_request_ctx(req);
struct crypto_tfm *tfm = req->base.tfm;
dma_addr_t src_addr, dst_addr;
+ bool use_bounce_src = false;
int cpu, ret = 0;
struct iaa_wq *iaa_wq;
struct device *dev;
struct idxd_wq *wq;
+ struct page *page;
+
+ req_ctx->bounce_src = NULL;
+ req_ctx->bounce_src_dma = 0;
+ req_ctx->bounce_src_len = 0;
if (!iaa_crypto_enabled) {
pr_debug("iaa_crypto disabled, not decompressing\n");
@@ -1601,10 +1641,16 @@ static int iaa_comp_adecompress(struct acomp_req *req)
return -EINVAL;
}
- /* Fall back to software if src or dst has multiple sg entries */
- if (sg_nents(req->src) > 1 || sg_nents(req->dst) > 1)
+ /* Fall back to software if dst has multiple sg entries */
+ if (sg_nents(req->dst) > 1)
return deflate_generic_decompress(req);
+ if (sg_nents(req->src) > 1) {
+ if (req->slen > PAGE_SIZE)
+ return deflate_generic_decompress(req);
+ use_bounce_src = true;
+ }
+
cpu = get_cpu();
wq = wq_table_next_wq(cpu);
put_cpu();
@@ -1623,20 +1669,47 @@ static int iaa_comp_adecompress(struct acomp_req *req)
dev = &wq->idxd->pdev->dev;
- if (!dma_map_sg(dev, req->src, 1, DMA_TO_DEVICE)) {
- dev_dbg(dev, "couldn't map src sg for iaa device %d, wq %d\n",
- iaa_wq->iaa_device->idxd->id, iaa_wq->wq->id);
- iaa_wq_put(wq);
- return deflate_generic_decompress(req);
+ if (unlikely(use_bounce_src)) {
+ page = mempool_alloc(iaa_bounce_pool, GFP_ATOMIC);
+ if (!page) {
+ iaa_wq_put(wq);
+ return deflate_generic_decompress(req);
+ }
+
+ if (sg_copy_to_buffer(req->src, sg_nents(req->src),
+ page_address(page), req->slen) != req->slen) {
+ mempool_free(page, iaa_bounce_pool);
+ iaa_wq_put(wq);
+ return deflate_generic_decompress(req);
+ }
+
+ src_addr = dma_map_page(dev, page, 0, req->slen, DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, src_addr)) {
+ mempool_free(page, iaa_bounce_pool);
+ iaa_wq_put(wq);
+ return deflate_generic_decompress(req);
+ }
+
+ req_ctx->bounce_src = page;
+ req_ctx->bounce_src_dma = src_addr;
+ req_ctx->bounce_src_len = req->slen;
+ } else {
+ if (!dma_map_sg(dev, req->src, 1, DMA_TO_DEVICE)) {
+ dev_dbg(dev, "couldn't map src sg for iaa device %d, wq %d\n",
+ iaa_wq->iaa_device->idxd->id, iaa_wq->wq->id);
+ iaa_wq_put(wq);
+ return deflate_generic_decompress(req);
+ }
+
+ src_addr = sg_dma_address(req->src);
+ dev_dbg(dev, "map src %llx req->src %p slen %d sg_len %d\n", src_addr,
+ req->src, req->slen, sg_dma_len(req->src));
}
- src_addr = sg_dma_address(req->src);
- dev_dbg(dev, "map src %llx req->src %p slen %d sg_len %d\n", src_addr,
- req->src, req->slen, sg_dma_len(req->src));
if (!dma_map_sg(dev, req->dst, 1, DMA_FROM_DEVICE)) {
dev_dbg(dev, "couldn't map dst sg for iaa device %d, wq %d\n",
iaa_wq->iaa_device->idxd->id, iaa_wq->wq->id);
- dma_unmap_sg(dev, req->src, 1, DMA_TO_DEVICE);
+ iaa_unmap_src(dev, req);
iaa_wq_put(wq);
return deflate_generic_decompress(req);
}
@@ -1653,7 +1726,7 @@ static int iaa_comp_adecompress(struct acomp_req *req)
dev_dbg(dev, "asynchronous decompress failed ret=%d\n", ret);
dma_unmap_sg(dev, req->dst, 1, DMA_FROM_DEVICE);
- dma_unmap_sg(dev, req->src, 1, DMA_TO_DEVICE);
+ iaa_unmap_src(dev, req);
iaa_wq_put(wq);
return ret;
@@ -1687,7 +1760,7 @@ static struct acomp_alg iaa_acomp_fixed_deflate = {
.cra_driver_name = "deflate-iaa",
.cra_flags = CRYPTO_ALG_ASYNC,
.cra_ctxsize = sizeof(struct iaa_compression_ctx),
- .cra_reqsize = sizeof(u32),
+ .cra_reqsize = sizeof(struct iaa_req_ctx),
.cra_module = THIS_MODULE,
.cra_priority = IAA_ALG_PRIORITY,
}
@@ -1886,6 +1959,12 @@ static int __init iaa_crypto_init_module(void)
goto err_aecs_init;
}
+ iaa_bounce_pool = mempool_create_page_pool(IAA_BOUNCE_POOL_SIZE, 0);
+ if (!iaa_bounce_pool) {
+ ret = -ENOMEM;
+ goto err_bounce_pool;
+ }
+
ret = idxd_driver_register(&iaa_crypto_driver);
if (ret) {
pr_debug("IAA wq sub-driver registration failed\n");
@@ -1919,6 +1998,9 @@ static int __init iaa_crypto_init_module(void)
err_verify_attr_create:
idxd_driver_unregister(&iaa_crypto_driver);
err_driver_reg:
+ mempool_destroy(iaa_bounce_pool);
+ iaa_bounce_pool = NULL;
+err_bounce_pool:
iaa_aecs_cleanup_fixed();
err_aecs_init:
@@ -1935,6 +2017,8 @@ static void __exit iaa_crypto_cleanup_module(void)
driver_remove_file(&iaa_crypto_driver.drv,
&driver_attr_verify_compress);
idxd_driver_unregister(&iaa_crypto_driver);
+ mempool_destroy(iaa_bounce_pool);
+ iaa_bounce_pool = NULL;
iaa_aecs_cleanup_fixed();
pr_debug("cleaned up\n");
--
2.55.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v2 5/5] crypto: iaa - unmap dst before software fallback on decompress
2026-08-05 21:19 [PATCH v2 0/5] crypto: iaa - Fixes for multi entry SG lists Vinicius Costa Gomes
` (3 preceding siblings ...)
2026-08-05 21:19 ` [PATCH v2 4/5] crypto: iaa - use bounce buffer for multi-sg decompress input Vinicius Costa Gomes
@ 2026-08-05 21:19 ` Vinicius Costa Gomes
4 siblings, 0 replies; 10+ messages in thread
From: Vinicius Costa Gomes @ 2026-08-05 21:19 UTC (permalink / raw)
To: Dave Jiang, Vinod Koul, Frank Li, Kristen Accardi, Herbert Xu,
David S. Miller, Andrew Morton, Yosry Ahmed, Nhat Pham
Cc: dmaengine, linux-kernel, linux-crypto, Vinicius Costa Gomes,
stable
On a hardware analytics error, decompress retries through the software
fallback, which writes req->dst with the CPU while it is still mapped
DMA_FROM_DEVICE. With SWIOTLB active the later dma_unmap_sg() copies the
stale bounce buffer over req->dst, corrupting the result.
Unmap before the fallback runs. The async path unmaps inline; the sync
path signals the retry with -EAGAIN so iaa_comp_adecompress() runs the
fallback after unmapping.
Fixes: 2ec6761df889 ("crypto: iaa - Add support for deflate-iaa compression algorithm")
Cc: stable@vger.kernel.org
Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
---
drivers/crypto/intel/iaa/iaa_crypto_main.c | 35 +++++++++++++++---------------
1 file changed, 18 insertions(+), 17 deletions(-)
diff --git a/drivers/crypto/intel/iaa/iaa_crypto_main.c b/drivers/crypto/intel/iaa/iaa_crypto_main.c
index 51547c5fcf70..c9ab4b83ae02 100644
--- a/drivers/crypto/intel/iaa/iaa_crypto_main.c
+++ b/drivers/crypto/intel/iaa/iaa_crypto_main.c
@@ -995,6 +995,11 @@ static inline int check_completion(struct device *dev,
return ret;
}
+static bool iaa_error_should_retry(struct idxd_desc *idxd_desc)
+{
+ return idxd_desc->iax_completion->status == IAA_ANALYTICS_ERROR;
+}
+
static void iaa_unmap_src(struct device *dev, struct acomp_req *req)
{
struct iaa_req_ctx *req_ctx = acomp_request_ctx(req);
@@ -1082,18 +1087,21 @@ static void iaa_desc_complete(struct idxd_desc *idxd_desc,
ctx->compress, false);
if (ret) {
dev_dbg(dev, "%s: check_completion failed ret=%d\n", __func__, ret);
- if (!ctx->compress &&
- idxd_desc->iax_completion->status == IAA_ANALYTICS_ERROR) {
+ if (!ctx->compress && iaa_error_should_retry(idxd_desc)) {
pr_warn("%s: falling back to deflate-generic decompress, "
"analytics error code %x\n", __func__,
idxd_desc->iax_completion->error_code);
+ dma_unmap_sg(dev, ctx->req->dst, sg_nents(ctx->req->dst),
+ DMA_FROM_DEVICE);
+ iaa_unmap_src(dev, ctx->req);
+
ret = deflate_generic_decompress(ctx->req);
if (ret) {
dev_dbg(dev, "%s: deflate-generic failed ret=%d\n",
__func__, ret);
err = -EIO;
- goto err;
}
+ goto out;
} else {
err = -EIO;
goto err;
@@ -1477,19 +1485,9 @@ static int iaa_decompress(struct crypto_tfm *tfm, struct acomp_req *req,
ret = check_completion(dev, idxd_desc->iax_completion, false, false);
if (ret) {
dev_dbg(dev, "%s: check_completion failed ret=%d\n", __func__, ret);
- if (idxd_desc->iax_completion->status == IAA_ANALYTICS_ERROR) {
- pr_warn("%s: falling back to deflate-generic decompress, "
- "analytics error code %x\n", __func__,
- idxd_desc->iax_completion->error_code);
- ret = deflate_generic_decompress(req);
- if (ret) {
- dev_dbg(dev, "%s: deflate-generic failed ret=%d\n",
- __func__, ret);
- goto err;
- }
- } else {
- goto err;
- }
+ if (iaa_error_should_retry(idxd_desc))
+ ret = -EAGAIN;
+ goto err;
} else {
req->dlen = idxd_desc->iax_completion->output_size;
@@ -1722,13 +1720,16 @@ static int iaa_comp_adecompress(struct acomp_req *req)
if (ret == -EINPROGRESS)
return ret;
- if (ret != 0)
+ if (ret != 0 && ret != -EAGAIN)
dev_dbg(dev, "asynchronous decompress failed ret=%d\n", ret);
dma_unmap_sg(dev, req->dst, 1, DMA_FROM_DEVICE);
iaa_unmap_src(dev, req);
iaa_wq_put(wq);
+ if (ret == -EAGAIN)
+ ret = deflate_generic_decompress(req);
+
return ret;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v2 3/5] crypto: iaa - avoid counting fallback decompression bytes
2026-08-05 21:19 ` [PATCH v2 3/5] crypto: iaa - avoid counting fallback decompression bytes Vinicius Costa Gomes
@ 2026-08-05 21:32 ` sashiko-bot
0 siblings, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-08-05 21:32 UTC (permalink / raw)
To: Vinicius Costa Gomes; +Cc: Frank.Li, dmaengine, vkoul
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
Pre-existing issues:
- [Critical] Software fallback decompression executes while scatterlist buffers are still mapped for DMA, leading to data corruption.
- [High] TOCTOU race condition leading to Use-After-Free of `wq_table` during device unbind.
- [High] Hardware DMA writes to freed memory if `check_completion` times out.
--
--- Patch [3]: [PATCH v2 3/5] crypto: iaa - avoid counting fallback decompression bytes ---
commit 4c267bc9414930f6e0fce0b302c075f74ec2f4ff
Author: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
crypto: iaa - avoid counting fallback decompression bytes
This commit moves decompression byte accounting into the successful IAA
completion path in both synchronous and asynchronous flows. This ensures
decomp_bytes only reflects bytes actually processed by IAA, avoiding counting
fallback decompression bytes when an analytics error occurs.
> diff --git a/drivers/crypto/intel/iaa/iaa_crypto_main.c b/drivers/crypto/intel/iaa/iaa_crypto_main.c
> index 904d9413ba182..9505ca23e6f38 100644
> --- a/drivers/crypto/intel/iaa/iaa_crypto_main.c
> +++ b/drivers/crypto/intel/iaa/iaa_crypto_main.c
> @@ -1071,15 +1071,17 @@ static void iaa_desc_complete(struct idxd_desc *idxd_desc,
> }
> } else {
> ctx->req->dlen = idxd_desc->iax_completion->output_size;
> +
> + if (!ctx->compress) {
> + update_total_decomp_bytes_in(ctx->req->slen);
> + update_wq_decomp_bytes(iaa_wq->wq, ctx->req->slen);
> + }
> }
[Severity: Critical]
This is a pre-existing issue, but can the software fallback decompression
execute while scatterlist buffers are still mapped for DMA, leading to data
corruption?
When the hardware engine returns IAA_ANALYTICS_ERROR and the operation
falls back to deflate_generic_decompress(), does it execute before
dma_unmap_sg() is called?
If the platform uses SWIOTLB bounce buffers, the hardware-untouched bounce
buffer could be copied back to the actual memory pages during unmap,
completely overwriting the CPU-decompressed valid data.
[ ... ]
> @@ -1462,16 +1464,16 @@ static int iaa_decompress(struct crypto_tfm *tfm, struct acomp_req *req,
> }
> } else {
> req->dlen = idxd_desc->iax_completion->output_size;
> +
> + /* Update stats */
> + update_total_decomp_bytes_in(slen);
> + update_wq_decomp_bytes(wq, slen);
> }
>
> *dlen = req->dlen;
>
> if (!ctx->async_mode)
> idxd_free_desc(wq, idxd_desc);
[Severity: High]
This is a pre-existing issue, but does a timeout in check_completion()
cause the hardware DMA to write to freed memory?
In check_completion(), if the hardware fails to complete the descriptor
within IAA_COMPLETION_TIMEOUT polls, the driver sets
iaa_crypto_enabled = false and returns -ETIMEDOUT.
The caller then frees the IDXD software descriptor and returns an error,
which leads to unmapping and freeing the SG buffers without aborting or
quiescing the hardware engine.
If the hardware is merely stalled and eventually completes the operation,
will it perform asynchronous DMA writes to the now-freed req->dst physical
pages, and write the completion status to the re-allocated descriptor?
[Severity: High]
This is a pre-existing issue, but is there a TOCTOU race condition
leading to a Use-After-Free of wq_table during device unbind?
The fast-paths like iaa_comp_acompress() check the global
iaa_crypto_enabled flag without locks:
if (!iaa_crypto_enabled) {
pr_debug("iaa_crypto disabled, not compressing\n");
return -ENODEV;
}
...
cpu = get_cpu();
wq = wq_table_next_wq(cpu);
Concurrently, iaa_crypto_remove() can be invoked via device unbind,
setting iaa_crypto_enabled = false and freeing the wq_table pointer array.
Since the crypto algorithms are only unregistered during module exit,
they remain accessible. Can a concurrent compression request read
iaa_crypto_enabled == true, get preempted, and then access the freed
wq_table when calling wq_table_next_wq()?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260805-iaa-crypto-fixes-zswap-v2-0-55c02694f499@intel.com?part=3
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 4/5] crypto: iaa - use bounce buffer for multi-sg decompress input
2026-08-05 21:19 ` [PATCH v2 4/5] crypto: iaa - use bounce buffer for multi-sg decompress input Vinicius Costa Gomes
@ 2026-08-05 21:36 ` sashiko-bot
0 siblings, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-08-05 21:36 UTC (permalink / raw)
To: Vinicius Costa Gomes; +Cc: dmaengine, Frank.Li, vkoul
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [Critical] Software fallback inside the synchronous `iaa_decompress()` path writes to `req->dst` while it remains mapped for DMA, causing data corruption when unmapped if SWIOTLB is active.
--
--- Patch [4]: [PATCH v2 4/5] crypto: iaa - use bounce buffer for multi-sg decompress input ---
commit 734c3b6227baae1deae54e3c6e85848a75b44265
Author: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
crypto: iaa - use bounce buffer for multi-sg decompress input
This commit introduces a pre-allocated bounce page to linearize small
multi-entry sources for IAA hardware decompression. This avoids falling
back to software for multi-entry sources while maintaining the fallback
for multi-entry destinations.
> diff --git a/drivers/crypto/intel/iaa/iaa_crypto_main.c b/drivers/crypto/intel/iaa/iaa_crypto_main.c
> index 9505ca23e6f38..51547c5fcf701 100644
> --- a/drivers/crypto/intel/iaa/iaa_crypto_main.c
> +++ b/drivers/crypto/intel/iaa/iaa_crypto_main.c
[ ... ]
> @@ -1653,7 +1726,7 @@ static int iaa_comp_adecompress(struct acomp_req *req)
> dev_dbg(dev, "asynchronous decompress failed ret=%d\n", ret);
>
> dma_unmap_sg(dev, req->dst, 1, DMA_FROM_DEVICE);
> - dma_unmap_sg(dev, req->src, 1, DMA_TO_DEVICE);
> + iaa_unmap_src(dev, req);
> iaa_wq_put(wq);
[Severity: Critical]
This is a pre-existing issue, but since this patch modifies the unmap
path here, I noticed a potential data corruption issue when SWIOTLB is
active.
If iaa_decompress() fails and falls back to software via
deflate_generic_decompress(req), the CPU will write valid decompressed
data directly to req->dst.
However, req->dst is still mapped for DMA (DMA_FROM_DEVICE). When
iaa_decompress() returns success after the fallback, we reach this
dma_unmap_sg() in iaa_comp_adecompress():
iaa_comp_adecompress()
dma_map_sg(..., req->dst, DMA_FROM_DEVICE);
...
ret = iaa_decompress(...)
-> hardware fails, falls back to deflate_generic_decompress(req)
-> CPU writes decompressed data to req->dst
-> returns 0
dma_unmap_sg(..., req->dst, DMA_FROM_DEVICE);
If SWIOTLB is active, won't this dma_unmap_sg() copy the unmodified or
partially modified bounce buffer back over req->dst, overwriting the
valid CPU-written data with garbage?
Should the software fallback inside iaa_decompress() unmap req->dst before
calling deflate_generic_decompress(req), similar to how
iaa_desc_complete() handles its fallback?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260805-iaa-crypto-fixes-zswap-v2-0-55c02694f499@intel.com?part=4
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 2/5] crypto: iaa - fall back to software for multi-entry scatterlists
2026-08-05 21:19 ` [PATCH v2 2/5] crypto: iaa - fall back to software for multi-entry scatterlists Vinicius Costa Gomes
@ 2026-08-05 21:38 ` sashiko-bot
0 siblings, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-08-05 21:38 UTC (permalink / raw)
To: Vinicius Costa Gomes; +Cc: Frank.Li, vkoul, dmaengine
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Software decompression fallback reads and writes buffers while they are still DMA-mapped, leading to data corruption on systems using SWIOTLB (bounce buffers).
--
--- Patch [2]: [PATCH v2 2/5] crypto: iaa - fall back to software for multi-entry scatterlists ---
commit 6596711a82477095464512f0a5cfb3f894ac8fad
Author: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
Subject: crypto: iaa - fall back to software for multi-entry scatterlists
This commit routes multi-entry scatterlists to a software deflate
implementation instead of failing them. It simplifies the DMA mapping
paths to handle only single entries and falls back to software on mapping
failures. Counters are added to track the number of software fallback
compressions.
Cc: stable@vger.kernel.org
> diff --git a/drivers/crypto/intel/iaa/iaa_crypto_main.c b/drivers/crypto/intel/iaa/iaa_crypto_main.c
> index f62b994e18e58..904d9413ba182 100644
> --- a/drivers/crypto/intel/iaa/iaa_crypto_main.c
> +++ b/drivers/crypto/intel/iaa/iaa_crypto_main.c
[ ... ]
> @@ -1639,10 +1650,8 @@ static int iaa_comp_adecompress(struct acomp_req *req)
> 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:
> + dma_unmap_sg(dev, req->dst, 1, DMA_FROM_DEVICE);
> + dma_unmap_sg(dev, req->src, 1, DMA_TO_DEVICE);
> iaa_wq_put(wq);
>
> return ret;
[Severity: High]
This is a pre-existing issue, but can the software fallback logic corrupt
data on systems using SWIOTLB (bounce buffers)?
If hardware decompression fails with an analytics error (for example,
IAA_ANALYTICS_ERROR), the driver falls back to software decompression via
deflate_generic_decompress(). This fallback executes directly on the CPU,
modifying the original virtual pages.
In the async completion path, the software fallback is executed while the
buffers are still actively DMA-mapped:
iaa_crypto_main.c:iaa_desc_complete() {
...
if (err == IAA_ANALYTICS_ERROR) {
ret = deflate_generic_decompress(ctx->req);
...
dma_unmap_sg(dev, req->dst, 1, DMA_FROM_DEVICE);
}
When SWIOTLB is active, this unmap operation syncs the bounce buffer back
to the original memory. Does this completely overwrite the correct data just
produced by the software fallback with stale hardware garbage?
Could the driver unmap the buffers before falling back to software
decompression to prevent this?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260805-iaa-crypto-fixes-zswap-v2-0-55c02694f499@intel.com?part=2
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 1/5] dmaengine: idxd: assign all engines to group 0 in IAA defaults
2026-08-05 21:19 ` [PATCH v2 1/5] dmaengine: idxd: assign all engines to group 0 in IAA defaults Vinicius Costa Gomes
@ 2026-08-05 21:41 ` sashiko-bot
0 siblings, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-08-05 21:41 UTC (permalink / raw)
To: Vinicius Costa Gomes; +Cc: dmaengine, Frank.Li, vkoul
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Blind array access to `idxd->wqs[0]` and `idxd->groups[0]` crashes the kernel if the device reports 0 for max workqueues or max groups.
--
--- Patch [1]: [PATCH v2 1/5] dmaengine: idxd: assign all engines to group 0 in IAA defaults ---
commit 209df0dc4b3ef9ed572aa6087272c2bf0872b76a
Author: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
Subject: dmaengine: idxd: assign all engines to group 0 in IAA defaults
This commit updates the IAA device defaults to assign all available engines
to group 0. This change ensures that the full hardware parallelism is used
by default without requiring manual accel-config setup.
> diff --git a/drivers/dma/idxd/defaults.c b/drivers/dma/idxd/defaults.c
> index 2bbbcd02a0dac..26ebfa2ca1448 100644
> --- a/drivers/dma/idxd/defaults.c
> +++ b/drivers/dma/idxd/defaults.c
> @@ -8,6 +8,7 @@ int idxd_load_iaa_device_defaults(struct idxd_device *idxd)
> struct idxd_engine *engine;
> struct idxd_group *group;
> struct idxd_wq *wq;
> + int i;
>
> if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
> return 0;
[Severity: High]
This is a pre-existing issue, but does idxd_load_iaa_device_defaults()
safely handle devices that report 0 workqueues or groups?
If a malfunctioning device reports 0 for max_wqs or max_groups during probe,
the setup routines will allocate 0-sized arrays. This function later accesses
the first elements without checking the bounds:
idxd_load_iaa_device_defaults()
{
...
wq = idxd->wqs[0];
...
group = idxd->groups[0];
...
}
Would this lead to a kernel panic by dereferencing a zero-size pointer
if the device capabilities are malformed?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260805-iaa-crypto-fixes-zswap-v2-0-55c02694f499@intel.com?part=1
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-08-05 21:41 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-05 21:19 [PATCH v2 0/5] crypto: iaa - Fixes for multi entry SG lists Vinicius Costa Gomes
2026-08-05 21:19 ` [PATCH v2 1/5] dmaengine: idxd: assign all engines to group 0 in IAA defaults Vinicius Costa Gomes
2026-08-05 21:41 ` sashiko-bot
2026-08-05 21:19 ` [PATCH v2 2/5] crypto: iaa - fall back to software for multi-entry scatterlists Vinicius Costa Gomes
2026-08-05 21:38 ` sashiko-bot
2026-08-05 21:19 ` [PATCH v2 3/5] crypto: iaa - avoid counting fallback decompression bytes Vinicius Costa Gomes
2026-08-05 21:32 ` sashiko-bot
2026-08-05 21:19 ` [PATCH v2 4/5] crypto: iaa - use bounce buffer for multi-sg decompress input Vinicius Costa Gomes
2026-08-05 21:36 ` sashiko-bot
2026-08-05 21:19 ` [PATCH v2 5/5] crypto: iaa - unmap dst before software fallback on decompress Vinicius Costa Gomes
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox