Implement SMT sibling auto-isolation logic via 'smt_aware_mode' sysfs node. When enabled, writing to housekeeping masks will automatically ensure that all siblings of a physical core stay together in the same isolation state.
Also implement a safety check in housekeeping_store() to ensure that at least one online CPU remains as housekeeping, preventing the user from accidentally isolating all CPUs and locking up the system. Signed-off-by: Qiliang Yuan <[email protected]> Signed-off-by: Qiliang Yuan <[email protected]> --- kernel/sched/isolation.c | 72 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 67 insertions(+), 5 deletions(-) diff --git a/kernel/sched/isolation.c b/kernel/sched/isolation.c index d9ce26cf31fe..30798e790b9f 100644 --- a/kernel/sched/isolation.c +++ b/kernel/sched/isolation.c @@ -13,6 +13,7 @@ #include <linux/sysfs.h> #include <linux/slab.h> #include <linux/ctype.h> +#include <linux/topology.h> #include "sched.h" enum hk_flags { @@ -40,6 +41,30 @@ struct housekeeping { }; static struct housekeeping housekeeping; +static bool housekeeping_smt_aware; + +static ssize_t smt_aware_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", housekeeping_smt_aware); +} + +static ssize_t smt_aware_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + bool val; + + if (kstrtobool(buf, &val)) + return -EINVAL; + + housekeeping_smt_aware = val; + + return count; +} + +static struct kobj_attribute smt_aware_attr = + __ATTR(smt_aware_mode, 0644, smt_aware_show, smt_aware_store); bool housekeeping_enabled(enum hk_type type) { @@ -164,11 +189,40 @@ static ssize_t housekeeping_store(struct kobject *kobject, if (err) goto out_free; - if (cpumask_empty(new_mask)) { + /* Safety check: must have at least one online CPU for housekeeping */ + if (!cpumask_intersects(new_mask, cpu_online_mask)) { err = -EINVAL; goto out_free; } + if (housekeeping_smt_aware) { + int cpu, sibling; + cpumask_var_t tmp_mask; + + if (!alloc_cpumask_var(&tmp_mask, GFP_KERNEL)) { + err = -ENOMEM; + goto out_free; + } + + cpumask_copy(tmp_mask, new_mask); + for_each_cpu(cpu, tmp_mask) { + for_each_cpu(sibling, topology_sibling_cpumask(cpu)) { + if (!cpumask_test_cpu(sibling, tmp_mask)) { + /* SMT sibling should stay grouped */ + cpumask_clear_cpu(cpu, new_mask); + break; + } + } + } + free_cpumask_var(tmp_mask); + + /* Re-check after SMT sync */ + if (!cpumask_intersects(new_mask, cpu_online_mask)) { + err = -EINVAL; + goto out_free; + } + } + mutex_lock(&housekeeping_mutex); if (!housekeeping.cpumasks[type]) { @@ -230,12 +284,20 @@ static int __init housekeeping_sysfs_init(void) housekeeping_attr_ptr[j] = NULL; ret = sysfs_create_group(housekeeping_kobj, &housekeeping_attr_group); - if (ret) { - kobject_put(housekeeping_kobj); - return ret; - } + if (ret) + goto err_group; + + ret = sysfs_create_file(housekeeping_kobj, &smt_aware_attr.attr); + if (ret) + goto err_file; return 0; + +err_file: + sysfs_remove_group(housekeeping_kobj, &housekeeping_attr_group); +err_group: + kobject_put(housekeeping_kobj); + return ret; } late_initcall(housekeeping_sysfs_init); -- 2.51.0

