@@ -102,9 +102,9 @@ void mktme_percpu_ref_release(struct percpu_ref *ref)
return;
}
percpu_ref_exit(ref);
- spin_lock_irqsave(&mktme_map_lock, flags);
+ spin_lock_irqsave(&mktme_lock, flags);
mktme_release_keyid(keyid);
- spin_unlock_irqrestore(&mktme_map_lock, flags);
+ spin_unlock_irqrestore(&mktme_lock, flags);
}
enum mktme_opt_id {
@@ -506,9 +506,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_map->mapped_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)
@@ -553,10 +590,18 @@ static int __init init_mktme(void)
if (!mktme_key_store)
goto free_bitmap;
+ cpuhp = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
+ "keys/mktme_keys:online",
+ NULL, mktme_cpu_teardown);
+ if (cpuhp < 0)
+ goto free_store;
+
ret = register_key_type(&key_type_mktme);
if (!ret)
return ret; /* SUCCESS */
+ cpuhp_remove_state_nocalls(cpuhp);
+free_store:
kfree(mktme_key_store);
free_bitmap:
bitmap_free(mktme_bitmap_user_type);