@@ -460,9 +460,46 @@ static int mktme_alloc_pconfig_targets(void)
return 0;
}
+static int mktme_cpu_teardown(unsigned int cpu)
+{
+ int new_leadcpu, ret = 0;
+ unsigned long flags;
+
+ /* Do not allow key programming during cpu hotplug event */
+ spin_lock_irqsave(&mktme_lock, flags);
+
+ /*
+ * When no keys are in use, allow the teardown, and set
+ * mktme_allow_keys to FALSE. That forces an evaluation
+ * of the topology before the next key creation.
+ */
+ if (mktme_available_keyids == mktme_nr_keyids()) {
+ mktme_allow_keys = false;
+ goto out;
+ }
+ /* Teardown CPU is not a lead CPU. Allow teardown. */
+ if (!cpumask_test_cpu(cpu, mktme_leadcpus))
+ goto out;
+
+ /* Teardown CPU is a lead CPU. Look for a new lead CPU. */
+ new_leadcpu = cpumask_any_but(topology_core_cpumask(cpu), cpu);
+
+ if (new_leadcpu < nr_cpumask_bits) {
+ /* New lead CPU found. Update the programming mask */
+ __cpumask_clear_cpu(cpu, mktme_leadcpus);
+ __cpumask_set_cpu(new_leadcpu, mktme_leadcpus);
+ } else {
+ /* New lead CPU not found. Do not allow CPU teardown */
+ ret = -1;
+ }
+out:
+ spin_unlock_irqrestore(&mktme_lock, flags);
+ return ret;
+}
+
static int __init init_mktme(void)
{
- int ret;
+ int ret, cpuhp;
/* Verify keys are present */
if (mktme_nr_keyids() < 1)
@@ -500,10 +537,18 @@ static int __init init_mktme(void)
if (!encrypt_count)
goto free_targets;
+ cpuhp = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
+ "keys/mktme_keys:online",
+ NULL, mktme_cpu_teardown);
+ if (cpuhp < 0)
+ goto free_encrypt;
+
ret = register_key_type(&key_type_mktme);
if (!ret)
return ret; /* SUCCESS */
+ cpuhp_remove_state_nocalls(cpuhp);
+free_encrypt:
kvfree(encrypt_count);
free_targets:
free_cpumask_var(mktme_leadcpus);