aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Freudenberger <freude@linux.ibm.com>2020-09-01 12:48:14 +0200
committerHeiko Carstens <hca@linux.ibm.com>2020-11-09 11:21:00 +0100
commit43cb5a7c61186cde6eba344c43489b9cf95c68f8 (patch)
tree8ef2cdb0bf51f4075b720e3dacd553dfff6f18fe
parents390/ap: ap bus userspace notifications for some bus conditions (diff)
downloadlinux-dev-43cb5a7c61186cde6eba344c43489b9cf95c68f8.tar.xz
linux-dev-43cb5a7c61186cde6eba344c43489b9cf95c68f8.zip
s390/zcrypt/pkey: introduce zcrypt_wait_api_operational() function
The zcrypt api provides a new function to wait until the zcrypt api is operational: int zcrypt_wait_api_operational(void); The AP bus scan and the binding of ap devices to device drivers is an asynchronous job. This function waits until these initial jobs are done and so the zcrypt api should be ready to serve crypto requests - if there are resources available. The function uses an internal timeout of 60s. The very first caller will either wait for ap bus bindings complete or the timeout happens. This state will be remembered for further callers which will only be blocked until a decision is made (timeout or bindings complete). Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com> Signed-off-by: Harald Freudenberger <freude@linux.ibm.com> Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
-rw-r--r--drivers/s390/crypto/pkey_api.c15
-rw-r--r--drivers/s390/crypto/zcrypt_api.c66
-rw-r--r--drivers/s390/crypto/zcrypt_api.h2
3 files changed, 83 insertions, 0 deletions
diff --git a/drivers/s390/crypto/pkey_api.c b/drivers/s390/crypto/pkey_api.c
index dd84995049b9..cf23ce1b1146 100644
--- a/drivers/s390/crypto/pkey_api.c
+++ b/drivers/s390/crypto/pkey_api.c
@@ -150,6 +150,8 @@ static int pkey_skey2pkey(const u8 *key, struct pkey_protkey *pkey)
u16 cardnr, domain;
struct keytoken_header *hdr = (struct keytoken_header *)key;
+ zcrypt_wait_api_operational();
+
/*
* The cca_xxx2protkey call may fail when a card has been
* addressed where the master key was changed after last fetch
@@ -197,6 +199,8 @@ static int pkey_clr2ep11key(const u8 *clrkey, size_t clrkeylen,
u16 card, dom;
u32 nr_apqns, *apqns = NULL;
+ zcrypt_wait_api_operational();
+
/* build a list of apqns suitable for ep11 keys with cpacf support */
rc = ep11_findcard2(&apqns, &nr_apqns, 0xFFFF, 0xFFFF,
ZCRYPT_CEX7, EP11_API_V, NULL);
@@ -230,6 +234,8 @@ static int pkey_ep11key2pkey(const u8 *key, struct pkey_protkey *pkey)
u32 nr_apqns, *apqns = NULL;
struct ep11keyblob *kb = (struct ep11keyblob *) key;
+ zcrypt_wait_api_operational();
+
/* build a list of apqns suitable for this key */
rc = ep11_findcard2(&apqns, &nr_apqns, 0xFFFF, 0xFFFF,
ZCRYPT_CEX7, EP11_API_V, kb->wkvp);
@@ -436,6 +442,7 @@ static int pkey_nonccatok2pkey(const u8 *key, u32 keylen,
if (rc == 0)
break;
/* PCKMO failed, so try the CCA secure key way */
+ zcrypt_wait_api_operational();
rc = cca_clr2seckey(0xFFFF, 0xFFFF, t->keytype,
ckey.clrkey, tmpbuf);
if (rc == 0)
@@ -625,6 +632,8 @@ static int pkey_clr2seckey2(const struct pkey_apqn *apqns, size_t nr_apqns,
return -EINVAL;
}
+ zcrypt_wait_api_operational();
+
/* simple try all apqns from the list */
for (i = 0, rc = -ENODEV; i < nr_apqns; i++) {
card = apqns[i].card;
@@ -801,6 +810,8 @@ static int pkey_keyblob2pkey2(const struct pkey_apqn *apqns, size_t nr_apqns,
return -EINVAL;
}
+ zcrypt_wait_api_operational();
+
/* simple try all apqns from the list */
for (i = 0, rc = -ENODEV; i < nr_apqns; i++) {
card = apqns[i].card;
@@ -838,6 +849,8 @@ static int pkey_apqns4key(const u8 *key, size_t keylen, u32 flags,
if (keylen < sizeof(struct keytoken_header) || flags == 0)
return -EINVAL;
+ zcrypt_wait_api_operational();
+
if (hdr->type == TOKTYPE_NON_CCA
&& (hdr->version == TOKVER_EP11_AES_WITH_HEADER
|| hdr->version == TOKVER_EP11_ECC_WITH_HEADER)
@@ -941,6 +954,8 @@ static int pkey_apqns4keytype(enum pkey_key_type ktype,
int rc;
u32 _nr_apqns, *_apqns = NULL;
+ zcrypt_wait_api_operational();
+
if (ktype == PKEY_TYPE_CCA_DATA || ktype == PKEY_TYPE_CCA_CIPHER) {
u64 cur_mkvp = 0, old_mkvp = 0;
int minhwtype = ZCRYPT_CEX3C;
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
index f60f9fb25214..10206e4498d0 100644
--- a/drivers/s390/crypto/zcrypt_api.c
+++ b/drivers/s390/crypto/zcrypt_api.c
@@ -1992,6 +1992,72 @@ void zcrypt_rng_device_remove(void)
mutex_unlock(&zcrypt_rng_mutex);
}
+/*
+ * Wait until the zcrypt api is operational.
+ * The AP bus scan and the binding of ap devices to device drivers is
+ * an asynchronous job. This function waits until these initial jobs
+ * are done and so the zcrypt api should be ready to serve crypto
+ * requests - if there are resources available. The function uses an
+ * internal timeout of 60s. The very first caller will either wait for
+ * ap bus bindings complete or the timeout happens. This state will be
+ * remembered for further callers which will only be blocked until a
+ * decision is made (timeout or bindings complete).
+ * On timeout -ETIME is returned, on success the return value is 0.
+ */
+int zcrypt_wait_api_operational(void)
+{
+ static DEFINE_MUTEX(zcrypt_wait_api_lock);
+ static int zcrypt_wait_api_state;
+ int rc;
+
+ rc = mutex_lock_interruptible(&zcrypt_wait_api_lock);
+ if (rc)
+ return rc;
+
+ switch (zcrypt_wait_api_state) {
+ case 0:
+ /* initial state, invoke wait for the ap bus complete */
+ rc = ap_wait_init_apqn_bindings_complete(
+ msecs_to_jiffies(60 * 1000));
+ switch (rc) {
+ case 0:
+ /* ap bus bindings are complete */
+ zcrypt_wait_api_state = 1;
+ break;
+ case -EINTR:
+ /* interrupted, go back to caller */
+ break;
+ case -ETIME:
+ /* timeout */
+ ZCRYPT_DBF(DBF_WARN,
+ "%s ap_wait_init_apqn_bindings_complete() returned with ETIME\n",
+ __func__);
+ zcrypt_wait_api_state = -ETIME;
+ break;
+ default:
+ /* other failure */
+ ZCRYPT_DBF(DBF_DEBUG,
+ "%s ap_wait_init_apqn_bindings_complete() failure rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ break;
+ case 1:
+ /* a previous caller already found ap bus bindings complete */
+ rc = 0;
+ break;
+ default:
+ /* a previous caller had timeout or other failure */
+ rc = zcrypt_wait_api_state;
+ break;
+ }
+
+ mutex_unlock(&zcrypt_wait_api_lock);
+
+ return rc;
+}
+EXPORT_SYMBOL(zcrypt_wait_api_operational);
+
int __init zcrypt_debug_init(void)
{
zcrypt_dbf_info = debug_register("zcrypt", 1, 1,
diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h
index 51c0b8bdef50..16219efb2f61 100644
--- a/drivers/s390/crypto/zcrypt_api.h
+++ b/drivers/s390/crypto/zcrypt_api.h
@@ -162,6 +162,8 @@ void zcrypt_device_status_mask_ext(struct zcrypt_device_status_ext *devstatus);
int zcrypt_device_status_ext(int card, int queue,
struct zcrypt_device_status_ext *devstatus);
+int zcrypt_wait_api_operational(void);
+
static inline unsigned long z_copy_from_user(bool userspace,
void *to,
const void __user *from,