* [PATCH 1/3] s390/crypto: Rework ctr_aes_crypt() to remove conditional locking
2026-08-04 11:37 [PATCH 0/3] s390/crypto: Enable CONTEXT_ANALYSIS Heiko Carstens
@ 2026-08-04 11:37 ` Heiko Carstens
2026-08-04 11:37 ` [PATCH 2/3] s390/crypto: Rework ctr_paes_do_crypt() " Heiko Carstens
2026-08-04 11:37 ` [PATCH 3/3] s390/crypto: Enable CONTEXT_ANALYSIS Heiko Carstens
2 siblings, 0 replies; 4+ messages in thread
From: Heiko Carstens @ 2026-08-04 11:37 UTC (permalink / raw)
To: Harald Freudenberger, Holger Dengler, Herbert Xu
Cc: Alexander Gordeev, Sven Schnelle, Vasily Gorbik,
Christian Borntraeger, linux-s390, linux-kernel, linux-crypto
Clang's compiler based static context analysis does not work with locks
that are conditionally taken like in ctr_aes_crypt():
arch/s390/crypto/aes_s390.c:585:13: warning: mutex 'ctrblk_lock' is not held on every path through here
[-Wthread-safety-analysis]
585 | ctrptr = (n > AES_BLOCK_SIZE) ? ctrblk : walk.iv;
| ^
Given that code which takes locks conditionally can be considered
suboptimal rework ctr_aes_crypt() to get rid of this.
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
---
arch/s390/crypto/aes_s390.c | 54 ++++++++++++++++++++++++-------------
1 file changed, 35 insertions(+), 19 deletions(-)
diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c
index 62edc66d5478..4b7e47423e89 100644
--- a/arch/s390/crypto/aes_s390.c
+++ b/arch/s390/crypto/aes_s390.c
@@ -562,37 +562,53 @@ static unsigned int __ctrblk_init(u8 *ctrptr, u8 *iv, unsigned int nbytes)
return n;
}
+static int __ctr_aes_crypt(struct s390_aes_ctx *sctx,
+ struct skcipher_walk *walk, bool locked)
+{
+ unsigned int n, nbytes;
+ int ret = 0;
+ u8 *ctrptr;
+
+ while ((nbytes = walk->nbytes) >= AES_BLOCK_SIZE) {
+ n = AES_BLOCK_SIZE;
+ if (nbytes >= 2 * AES_BLOCK_SIZE && locked)
+ n = __ctrblk_init(ctrblk, walk->iv, nbytes);
+ ctrptr = (n > AES_BLOCK_SIZE) ? ctrblk : walk->iv;
+ cpacf_kmctr(sctx->fc, sctx->key, walk->dst.virt.addr,
+ walk->src.virt.addr, n, ctrptr);
+ if (ctrptr == ctrblk) {
+ memcpy(walk->iv, ctrptr + n - AES_BLOCK_SIZE,
+ AES_BLOCK_SIZE);
+ }
+ crypto_inc(walk->iv, AES_BLOCK_SIZE);
+ ret = skcipher_walk_done(walk, nbytes - n);
+ }
+
+ return ret;
+}
+
static int ctr_aes_crypt(struct skcipher_request *req)
{
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
struct s390_aes_ctx *sctx = crypto_skcipher_ctx(tfm);
- u8 buf[AES_BLOCK_SIZE], *ctrptr;
struct skcipher_walk walk;
- unsigned int n, nbytes;
- int ret, locked;
+ u8 buf[AES_BLOCK_SIZE];
+ unsigned int nbytes;
+ int ret;
if (unlikely(!sctx->fc))
return fallback_skcipher_crypt(sctx, req, 0);
- locked = mutex_trylock(&ctrblk_lock);
-
ret = skcipher_walk_virt(&walk, req, false);
- while ((nbytes = walk.nbytes) >= AES_BLOCK_SIZE) {
- n = AES_BLOCK_SIZE;
- if (nbytes >= 2*AES_BLOCK_SIZE && locked)
- n = __ctrblk_init(ctrblk, walk.iv, nbytes);
- ctrptr = (n > AES_BLOCK_SIZE) ? ctrblk : walk.iv;
- cpacf_kmctr(sctx->fc, sctx->key, walk.dst.virt.addr,
- walk.src.virt.addr, n, ctrptr);
- if (ctrptr == ctrblk)
- memcpy(walk.iv, ctrptr + n - AES_BLOCK_SIZE,
- AES_BLOCK_SIZE);
- crypto_inc(walk.iv, AES_BLOCK_SIZE);
- ret = skcipher_walk_done(&walk, nbytes - n);
- }
- if (locked)
+ if (mutex_trylock(&ctrblk_lock)) {
+ ret = __ctr_aes_crypt(sctx, &walk, true);
mutex_unlock(&ctrblk_lock);
+ } else {
+ ret = __ctr_aes_crypt(sctx, &walk, false);
+ }
+
+ nbytes = walk.nbytes;
/*
* final block may be < AES_BLOCK_SIZE, copy only nbytes
*/
--
2.53.0
^ permalink raw reply related [flat|nested] 4+ messages in thread* [PATCH 2/3] s390/crypto: Rework ctr_paes_do_crypt() to remove conditional locking
2026-08-04 11:37 [PATCH 0/3] s390/crypto: Enable CONTEXT_ANALYSIS Heiko Carstens
2026-08-04 11:37 ` [PATCH 1/3] s390/crypto: Rework ctr_aes_crypt() to remove conditional locking Heiko Carstens
@ 2026-08-04 11:37 ` Heiko Carstens
2026-08-04 11:37 ` [PATCH 3/3] s390/crypto: Enable CONTEXT_ANALYSIS Heiko Carstens
2 siblings, 0 replies; 4+ messages in thread
From: Heiko Carstens @ 2026-08-04 11:37 UTC (permalink / raw)
To: Harald Freudenberger, Holger Dengler, Herbert Xu
Cc: Alexander Gordeev, Sven Schnelle, Vasily Gorbik,
Christian Borntraeger, linux-s390, linux-kernel, linux-crypto
Clang's compiler based static context analysis does not work with locks
that are conditionally taken like in ctr_paes_do_crypt():
arch/s390/crypto/paes_s390.c:980:13: warning: mutex 'ctrblk_lock' is not held on every path through here
[-Wthread-safety-analysis]
980 | ctrptr = (n > AES_BLOCK_SIZE) ? ctrblk : walk->iv;
| ^
Given that code which takes locks conditionally can be considered
suboptimal rework ctr_paes_do_crypt() to get rid of this.
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
---
arch/s390/crypto/paes_s390.c | 104 ++++++++++++++++++++---------------
1 file changed, 60 insertions(+), 44 deletions(-)
diff --git a/arch/s390/crypto/paes_s390.c b/arch/s390/crypto/paes_s390.c
index 8cfe6166c193..d4a9108d39f5 100644
--- a/arch/s390/crypto/paes_s390.c
+++ b/arch/s390/crypto/paes_s390.c
@@ -932,15 +932,63 @@ static inline unsigned int __ctrblk_init(u8 *ctrptr, u8 *iv, unsigned int nbytes
return n;
}
+static int __ctr_paes_do_crypt(struct s390_paes_ctx *ctx,
+ struct s390_pctr_req_ctx *req_ctx,
+ bool tested, bool maysleep, bool locked)
+{
+ struct skcipher_walk *walk = &req_ctx->walk;
+ struct ctr_param *param = &req_ctx->param;
+ unsigned int nbytes, n, k;
+ u8 *ctrptr;
+ int rc = 0;
+
+ /*
+ * Note that in case of partial processing or failure the walk
+ * is NOT unmapped here. So a follow up task may reuse the walk
+ * or in case of unrecoverable failure needs to unmap it.
+ */
+ while ((nbytes = walk->nbytes) >= AES_BLOCK_SIZE) {
+ n = AES_BLOCK_SIZE;
+ if (nbytes >= 2 * AES_BLOCK_SIZE && locked)
+ n = __ctrblk_init(ctrblk, walk->iv, nbytes);
+ ctrptr = (n > AES_BLOCK_SIZE) ? ctrblk : walk->iv;
+ k = cpacf_kmctr(ctx->fc, param, walk->dst.virt.addr,
+ walk->src.virt.addr, n, ctrptr);
+ if (k) {
+ if (ctrptr == ctrblk) {
+ memcpy(walk->iv, ctrptr + k - AES_BLOCK_SIZE,
+ AES_BLOCK_SIZE);
+ }
+ crypto_inc(walk->iv, AES_BLOCK_SIZE);
+ rc = skcipher_walk_done(walk, nbytes - k);
+ }
+ if (k < n) {
+ if (!maysleep) {
+ rc = -EKEYEXPIRED;
+ goto out;
+ }
+ rc = paes_convert_key(ctx, tested);
+ if (rc)
+ goto out;
+ spin_lock_bh(&ctx->pk_lock);
+ memcpy(param->key, ctx->pk.protkey, sizeof(param->key));
+ spin_unlock_bh(&ctx->pk_lock);
+ }
+ }
+
+out:
+ return rc;
+}
+
static int ctr_paes_do_crypt(struct s390_paes_ctx *ctx,
struct s390_pctr_req_ctx *req_ctx,
bool tested, bool maysleep)
{
- struct ctr_param *param = &req_ctx->param;
struct skcipher_walk *walk = &req_ctx->walk;
- u8 buf[AES_BLOCK_SIZE], *ctrptr;
- unsigned int nbytes, n, k;
- int pk_state, locked, rc = 0;
+ struct ctr_param *param = &req_ctx->param;
+ u8 buf[AES_BLOCK_SIZE];
+ int pk_state, rc = 0;
+ unsigned int nbytes;
if (!req_ctx->param_init_done) {
/* fetch and check protected key state */
@@ -966,49 +1014,17 @@ static int ctr_paes_do_crypt(struct s390_paes_ctx *ctx,
if (rc)
goto out;
- locked = mutex_trylock(&ctrblk_lock);
-
- /*
- * Note that in case of partial processing or failure the walk
- * is NOT unmapped here. So a follow up task may reuse the walk
- * or in case of unrecoverable failure needs to unmap it.
- */
- while ((nbytes = walk->nbytes) >= AES_BLOCK_SIZE) {
- n = AES_BLOCK_SIZE;
- if (nbytes >= 2 * AES_BLOCK_SIZE && locked)
- n = __ctrblk_init(ctrblk, walk->iv, nbytes);
- ctrptr = (n > AES_BLOCK_SIZE) ? ctrblk : walk->iv;
- k = cpacf_kmctr(ctx->fc, param, walk->dst.virt.addr,
- walk->src.virt.addr, n, ctrptr);
- if (k) {
- if (ctrptr == ctrblk)
- memcpy(walk->iv, ctrptr + k - AES_BLOCK_SIZE,
- AES_BLOCK_SIZE);
- crypto_inc(walk->iv, AES_BLOCK_SIZE);
- rc = skcipher_walk_done(walk, nbytes - k);
- }
- if (k < n) {
- if (!maysleep) {
- if (locked)
- mutex_unlock(&ctrblk_lock);
- rc = -EKEYEXPIRED;
- goto out;
- }
- rc = paes_convert_key(ctx, tested);
- if (rc) {
- if (locked)
- mutex_unlock(&ctrblk_lock);
- goto out;
- }
- spin_lock_bh(&ctx->pk_lock);
- memcpy(param->key, ctx->pk.protkey, sizeof(param->key));
- spin_unlock_bh(&ctx->pk_lock);
- }
- }
- if (locked)
+ if (mutex_trylock(&ctrblk_lock)) {
+ rc = __ctr_paes_do_crypt(ctx, req_ctx, tested, maysleep, true);
mutex_unlock(&ctrblk_lock);
+ } else {
+ rc = __ctr_paes_do_crypt(ctx, req_ctx, tested, maysleep, false);
+ }
+ if (rc)
+ goto out;
/* final block may be < AES_BLOCK_SIZE, copy only nbytes */
+ nbytes = walk->nbytes;
if (nbytes) {
memset(buf, 0, AES_BLOCK_SIZE);
memcpy(buf, walk->src.virt.addr, nbytes);
--
2.53.0
^ permalink raw reply related [flat|nested] 4+ messages in thread