There is a need for a do-not-allocate-memory path through the ap bus layer. When ap_init_apmsg() with the AP_MSG_FLAG_MEMPOOL xflag is called, instead of kmalloc() the ap message buffer is allocated from the ap_msg_pool. This pool only holds a limited amount of buffers: AP_MSG_POOL_MIN_ITEMS with the item size AP_DEFAULT_MAX_MSG_SIZE and exactly one of these items (if available) is returned if ap_init_apmsg() with the MEMPOOL flag is called. When this pool is exhausted and the MEMPOOL flag is effective, ap_init_apmsg() returns -ENOMEM without any attempt to allocate memory. The zcrypt layer may use this flag to indicate to the ap bus that the processing path for this message should not allocate memory. This is to prevent deadlocks with crypto and io for example with encrypted swap volumes. Signed-off-by: Harald Freudenberger <freude@xxxxxxxxxxxxx> --- drivers/s390/crypto/ap_bus.c | 59 +++++++++++++++++++++++++++----- drivers/s390/crypto/ap_bus.h | 3 +- drivers/s390/crypto/zcrypt_api.c | 10 +++--- 3 files changed, 57 insertions(+), 15 deletions(-) diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 4940eaf538e9..b585b5d11074 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -40,6 +40,7 @@ #include <linux/module.h> #include <asm/uv.h> #include <asm/chsc.h> +#include <linux/mempool.h> #include "ap_bus.h" #include "ap_debug.h" @@ -101,6 +102,21 @@ static struct ap_config_info *const ap_qci_info_old = &qci[1]; */ debug_info_t *ap_dbf_info; +/* + * There is a need for a do-not-allocate-memory path through the + * ap bus layer. When ap_init_apmsg() with the AP_MSG_FLAG_MEMPOOL + * xflag is called, instead of kmalloc() the ap message buffer is + * allocated from the ap_msg_pool. This pool only holds a limited + * amount of buffers: AP_MSG_POOL_MIN_ITEMS with the item size + * AP_DEFAULT_MAX_MSG_SIZE and exactly one of these items (if available) + * is returned if ap_init_apmsg() with the MEMPOOL flag is called. + * When this pool is exhausted and the MEMPOOL flag is effective, + * ap_init_apmsg() returns -ENOMEM without any attempt to allocate + * memory. + */ +#define AP_MSG_POOL_MIN_ITEMS 4 +static mempool_t *ap_msg_pool; + /* * AP bus rescan related things. */ @@ -546,16 +562,27 @@ static void ap_poll_thread_stop(void) #define is_card_dev(x) ((x)->parent == ap_root_device) #define is_queue_dev(x) ((x)->parent != ap_root_device) -/** +/* * ap_init_apmsg() - Initialize ap_message. - * Initialize a message before using. Otherwise this might result in - * unexpected behaviour. + * Initialize struct ap_message and allocate buffer to construct + * the ap message. */ -int ap_init_apmsg(struct ap_message *ap_msg) +int ap_init_apmsg(struct ap_message *ap_msg, u32 xflags) { - unsigned int maxmsgsize = atomic_read(&ap_max_msg_size); + unsigned int maxmsgsize; memset(ap_msg, 0, sizeof(*ap_msg)); + + if (xflags & AP_MSG_FLAG_MEMPOOL) { + ap_msg->msg = mempool_alloc_preallocated(ap_msg_pool); + if (!ap_msg->msg) + return -ENOMEM; + ap_msg->bufsize = AP_DEFAULT_MAX_MSG_SIZE; + ap_msg->flags |= AP_MSG_FLAG_MEMPOOL; + return 0; + } + + maxmsgsize = atomic_read(&ap_max_msg_size); ap_msg->msg = kmalloc(maxmsgsize, GFP_KERNEL); if (!ap_msg->msg) return -ENOMEM; @@ -565,14 +592,18 @@ int ap_init_apmsg(struct ap_message *ap_msg) } EXPORT_SYMBOL(ap_init_apmsg); -/** +/* * ap_release_apmsg() - Release ap_message. - * Releases all memory used internal within the ap_message struct - * Currently this is the message and private field. + * Cleanup struct ap_message and release all memory held. */ void ap_release_apmsg(struct ap_message *ap_msg) { - kfree_sensitive(ap_msg->msg); + if (ap_msg->flags & AP_MSG_FLAG_MEMPOOL) { + memzero_explicit(ap_msg->msg, ap_msg->bufsize); + mempool_free(ap_msg->msg, ap_msg_pool); + } else { + kfree_sensitive(ap_msg->msg); + } } EXPORT_SYMBOL(ap_release_apmsg); @@ -2461,6 +2492,14 @@ static int __init ap_module_init(void) /* init ap_queue hashtable */ hash_init(ap_queues); + /* create ap msg buffer memory pool */ + ap_msg_pool = mempool_create_kmalloc_pool(AP_MSG_POOL_MIN_ITEMS, + AP_DEFAULT_MAX_MSG_SIZE); + if (IS_ERR(ap_msg_pool)) { + ap_msg_pool = NULL; + goto out; + } + /* set up the AP permissions (ioctls, ap and aq masks) */ ap_perms_init(); @@ -2507,6 +2546,7 @@ static int __init ap_module_init(void) out_bus: bus_unregister(&ap_bus_type); out: + mempool_destroy(ap_msg_pool); ap_debug_exit(); return rc; } @@ -2517,6 +2557,7 @@ static void __exit ap_module_exit(void) ap_irq_exit(); root_device_unregister(ap_root_device); bus_unregister(&ap_bus_type); + mempool_destroy(ap_msg_pool); ap_debug_exit(); } diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index 3956a5e945bd..8b20506d6a60 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h @@ -240,8 +240,9 @@ struct ap_message { #define AP_MSG_FLAG_SPECIAL 0x0001 /* flag msg as 'special' with NQAP */ #define AP_MSG_FLAG_USAGE 0x0002 /* CCA, EP11: usage (no admin) msg */ #define AP_MSG_FLAG_ADMIN 0x0004 /* CCA, EP11: admin (=control) msg */ +#define AP_MSG_FLAG_MEMPOOL 0x0008 /* ap msg buffer via mempool */ -int ap_init_apmsg(struct ap_message *ap_msg); +int ap_init_apmsg(struct ap_message *ap_msg, u32 xflags); void ap_release_apmsg(struct ap_message *ap_msg); enum ap_sm_wait ap_sm_event(struct ap_queue *aq, enum ap_sm_event event); diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 78df25da0b95..ce5f7cb974b9 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -648,7 +648,7 @@ static long zcrypt_rsa_modexpo(struct ap_perms *perms, trace_s390_zcrypt_req(mex, TP_ICARSAMODEXPO); - rc = ap_init_apmsg(&ap_msg); + rc = ap_init_apmsg(&ap_msg, 0); if (rc) goto out; @@ -753,7 +753,7 @@ static long zcrypt_rsa_crt(struct ap_perms *perms, trace_s390_zcrypt_req(crt, TP_ICARSACRT); - rc = ap_init_apmsg(&ap_msg); + rc = ap_init_apmsg(&ap_msg, 0); if (rc) goto out; @@ -861,7 +861,7 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms, xcrb->status = 0; - rc = ap_init_apmsg(&ap_msg); + rc = ap_init_apmsg(&ap_msg, 0); if (rc) goto out; @@ -1045,7 +1045,7 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms, trace_s390_zcrypt_req(xcrb, TP_ZSENDEP11CPRB); - rc = ap_init_apmsg(&ap_msg); + rc = ap_init_apmsg(&ap_msg, 0); if (rc) goto out; @@ -1219,7 +1219,7 @@ static long zcrypt_rng(char *buffer) trace_s390_zcrypt_req(buffer, TP_HWRNGCPRB); - rc = ap_init_apmsg(&ap_msg); + rc = ap_init_apmsg(&ap_msg, 0); if (rc) goto out; rc = prep_rng_ap_msg(&ap_msg, &func_code, &domain); -- 2.43.0