Subsystem housekeeping masks are currently static and can only be set
via boot-time parameters (isolcpus, nohz_full, etc.). There is no
userspace interface to reconfigure these boundaries at runtime.

Implement the DHEI sysfs interface under /sys/kernel/housekeeping.

This enables userspace to independently reconfigure different kernel
services' affinities without a reboot.

Signed-off-by: Qiliang Yuan <[email protected]>
---
 kernel/sched/isolation.c | 89 ++++++++++++++++++++++++------------------------
 1 file changed, 45 insertions(+), 44 deletions(-)

diff --git a/kernel/sched/isolation.c b/kernel/sched/isolation.c
index 685cc0df1bd9f..1c867784d155b 100644
--- a/kernel/sched/isolation.c
+++ b/kernel/sched/isolation.c
@@ -8,7 +8,12 @@
  *
  */
 #include <linux/sched/isolation.h>
+#include <linux/capability.h>
 #include <linux/mutex.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
 #include <linux/notifier.h>
 #include <linux/topology.h>
 #include "sched.h"
@@ -16,9 +21,17 @@
 enum hk_flags {
        HK_FLAG_DOMAIN          = BIT(HK_TYPE_DOMAIN),
        HK_FLAG_MANAGED_IRQ     = BIT(HK_TYPE_MANAGED_IRQ),
-       HK_FLAG_KERNEL_NOISE    = BIT(HK_TYPE_KERNEL_NOISE),
+       HK_FLAG_TICK            = BIT(HK_TYPE_TICK),
+       HK_FLAG_TIMER           = BIT(HK_TYPE_TIMER),
+       HK_FLAG_RCU             = BIT(HK_TYPE_RCU),
+       HK_FLAG_MISC            = BIT(HK_TYPE_MISC),
+       HK_FLAG_WQ              = BIT(HK_TYPE_WQ),
+       HK_FLAG_KTHREAD         = BIT(HK_TYPE_KTHREAD),
 };
 
+#define HK_FLAG_KERNEL_NOISE (HK_FLAG_TICK | HK_FLAG_TIMER | HK_FLAG_RCU | \
+                             HK_FLAG_MISC | HK_FLAG_WQ | HK_FLAG_KTHREAD)
+
 static DEFINE_MUTEX(housekeeping_mutex);
 static BLOCKING_NOTIFIER_HEAD(housekeeping_notifier_list);
 DEFINE_STATIC_KEY_FALSE(housekeeping_overridden);
@@ -44,6 +57,9 @@ static ssize_t smt_aware_store(struct kobject *kobj,
 {
        bool val;
 
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
        if (kstrtobool(buf, &val))
                return -EINVAL;
 
@@ -53,7 +69,7 @@ static ssize_t smt_aware_store(struct kobject *kobj,
 }
 
 static struct kobj_attribute smt_aware_attr =
-       __ATTR(smt_aware_mode, 0644, smt_aware_show, smt_aware_store);
+       __ATTR(smt_aware_mode, 0600, smt_aware_show, smt_aware_store);
 
 bool housekeeping_enabled(enum hk_type type)
 {
@@ -171,6 +187,9 @@ static ssize_t housekeeping_store(struct kobject *kobject,
        cpumask_var_t new_mask;
        int err;
 
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
        if (!alloc_cpumask_var(&new_mask, GFP_KERNEL))
                return -ENOMEM;
 
@@ -178,42 +197,26 @@ static ssize_t housekeeping_store(struct kobject *kobject,
        if (err)
                goto out_free;
 
-       /* Safety check: must have at least one online CPU for housekeeping */
-       if (!cpumask_intersects(new_mask, cpu_online_mask)) {
+       if (cpumask_empty(new_mask) ||
+           !cpumask_intersects(new_mask, cpu_online_mask)) {
                err = -EINVAL;
                goto out_free;
        }
 
-       if (housekeeping_smt_aware) {
-               int cpu, sibling;
-               cpumask_var_t tmp_mask;
+       mutex_lock(&housekeeping_mutex);
 
-               if (!alloc_cpumask_var(&tmp_mask, GFP_KERNEL)) {
-                       err = -ENOMEM;
-                       goto out_free;
-               }
+       if (housekeeping_smt_aware) {
+               int cpu;
 
-               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;
-                               }
+               for_each_cpu(cpu, new_mask) {
+                       if (!cpumask_subset(topology_sibling_cpumask(cpu),
+                                           new_mask)) {
+                               err = -EINVAL;
+                               goto out_unlock;
                        }
                }
-               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]) {
                if (!alloc_cpumask_var(&housekeeping.cpumasks[type], 
GFP_KERNEL)) {
                        err = -ENOMEM;
@@ -242,7 +245,7 @@ static ssize_t housekeeping_store(struct kobject *kobject,
 }
 
 static struct hk_attribute housekeeping_attrs[HK_TYPE_MAX];
-static struct attribute *housekeeping_attr_ptr[HK_TYPE_MAX + 1];
+static struct attribute *housekeeping_attr_ptr[HK_TYPE_MAX + 2];
 
 static const struct attribute_group housekeeping_attr_group = {
        .attrs = housekeeping_attr_ptr,
@@ -265,28 +268,22 @@ static int __init housekeeping_sysfs_init(void)
                housekeeping_attrs[i].type = i;
                sysfs_attr_init(&housekeeping_attrs[i].kattr.attr);
                housekeeping_attrs[i].kattr.attr.name = hk_type_names[i];
-               housekeeping_attrs[i].kattr.attr.mode = 0644;
+               housekeeping_attrs[i].kattr.attr.mode = 0600;
                housekeeping_attrs[i].kattr.show = housekeeping_show;
                housekeeping_attrs[i].kattr.store = housekeeping_store;
                housekeeping_attr_ptr[j++] = &housekeeping_attrs[i].kattr.attr;
        }
+
+       housekeeping_attr_ptr[j++] = &smt_aware_attr.attr;
        housekeeping_attr_ptr[j] = NULL;
 
        ret = sysfs_create_group(housekeeping_kobj, &housekeeping_attr_group);
-       if (ret)
-               goto err_group;
-
-       ret = sysfs_create_file(housekeeping_kobj, &smt_aware_attr.attr);
-       if (ret)
-               goto err_file;
+       if (ret) {
+               kobject_put(housekeeping_kobj);
+               return ret;
+       }
 
        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);
 
@@ -313,8 +310,12 @@ static void __init housekeeping_setup_type(enum hk_type 
type,
        if (!slab_is_available())
                gfp = GFP_NOWAIT;
 
-       if (!housekeeping.cpumasks[type])
-               alloc_cpumask_var(&housekeeping.cpumasks[type], gfp);
+       if (!housekeeping.cpumasks[type]) {
+               if (!alloc_cpumask_var(&housekeeping.cpumasks[type], gfp)) {
+                       pr_err("housekeeping: failed to allocate cpumask for 
type %d\n", type);
+                       return;
+               }
+       }
 
        cpumask_copy(housekeeping.cpumasks[type],
                     housekeeping_staging);

-- 
2.43.0


Reply via email to