Extend housekeeping_dereference_check() to validate all runtime-mutable
types (HK_TYPE_DOMAIN, HK_TYPE_KERNEL_NOISE, HK_TYPE_MANAGED_IRQ), not
only HK_TYPE_DOMAIN.  Boot-only types (HK_TYPE_DOMAIN_BOOT) remain
unchecked.

Add housekeeping_cpumask_rcu() for callers that already hold an RCU
read lock.  This variant uses rcu_dereference() without the lockdep
annotation, avoiding false-positive lockdep warnings in RCU read-side
critical sections.

Use READ_ONCE() consistently when testing housekeeping.flags in paths
that may race with housekeeping_update_types().

Signed-off-by: Jing Wu <[email protected]>
Signed-off-by: Qiliang Yuan <[email protected]>
---
 include/linux/sched/isolation.h |  6 +++++
 kernel/sched/isolation.c        | 57 +++++++++++++++++++++++++++++++----------
 2 files changed, 49 insertions(+), 14 deletions(-)

diff --git a/include/linux/sched/isolation.h b/include/linux/sched/isolation.h
index eecbcbe802bd0..ed6e1c6980131 100644
--- a/include/linux/sched/isolation.h
+++ b/include/linux/sched/isolation.h
@@ -40,6 +40,7 @@ enum hk_type {
 DECLARE_STATIC_KEY_FALSE(housekeeping_overridden);
 extern int housekeeping_any_cpu(enum hk_type type);
 extern const struct cpumask *housekeeping_cpumask(enum hk_type type);
+extern const struct cpumask *housekeeping_cpumask_rcu(enum hk_type type);
 extern bool housekeeping_enabled(enum hk_type type);
 extern void housekeeping_affine(struct task_struct *t, enum hk_type type);
 extern bool housekeeping_test_cpu(int cpu, enum hk_type type);
@@ -87,6 +88,11 @@ static inline const struct cpumask 
*housekeeping_cpumask(enum hk_type type)
        return cpu_possible_mask;
 }
 
+static inline const struct cpumask *housekeeping_cpumask_rcu(enum hk_type type)
+{
+       return cpu_possible_mask;
+}
+
 static inline bool housekeeping_enabled(enum hk_type type)
 {
        return false;
diff --git a/kernel/sched/isolation.c b/kernel/sched/isolation.c
index 4eca18cc5e8ce..3d5d3f12853c7 100644
--- a/kernel/sched/isolation.c
+++ b/kernel/sched/isolation.c
@@ -121,25 +121,40 @@ bool housekeeping_enabled(enum hk_type type)
 }
 EXPORT_SYMBOL_GPL(housekeeping_enabled);
 
+/*
+ * Types that can change at runtime via cpuset isolated partitions.
+ * Boot-only types (DOMAIN_BOOT) are always safe to read without lockdep.
+ */
+static bool housekeeping_type_can_change(enum hk_type type)
+{
+       switch (type) {
+       case HK_TYPE_DOMAIN:
+       case HK_TYPE_KERNEL_NOISE:
+       case HK_TYPE_MANAGED_IRQ:
+               return true;
+       default:
+               return false;
+       }
+}
+
 static bool housekeeping_dereference_check(enum hk_type type)
 {
-       if (IS_ENABLED(CONFIG_LOCKDEP) && type == HK_TYPE_DOMAIN) {
-               /* Cpuset isn't even writable yet? */
-               if (system_state <= SYSTEM_SCHEDULING)
-                       return true;
+       if (!IS_ENABLED(CONFIG_LOCKDEP) || !housekeeping_type_can_change(type))
+               return true;
 
-               /* CPU hotplug write locked, so cpuset partition can't be 
overwritten */
-               if (IS_ENABLED(CONFIG_HOTPLUG_CPU) && 
lockdep_is_cpus_write_held())
-                       return true;
+       /* Cpuset isn't even writable yet? */
+       if (system_state <= SYSTEM_SCHEDULING)
+               return true;
 
-               /* Cpuset lock held, partitions not writable */
-               if (IS_ENABLED(CONFIG_CPUSETS) && lockdep_is_cpuset_held())
-                       return true;
+       /* CPU hotplug write locked, so cpuset partition can't be overwritten */
+       if (IS_ENABLED(CONFIG_HOTPLUG_CPU) && lockdep_is_cpus_write_held())
+               return true;
 
-               return false;
-       }
+       /* Cpuset lock held, partitions not writable */
+       if (IS_ENABLED(CONFIG_CPUSETS) && lockdep_is_cpuset_held())
+               return true;
 
-       return true;
+       return false;
 }
 
 static inline struct cpumask *housekeeping_cpumask_dereference(enum hk_type 
type)
@@ -162,12 +177,26 @@ const struct cpumask *housekeeping_cpumask(enum hk_type 
type)
 }
 EXPORT_SYMBOL_GPL(housekeeping_cpumask);
 
+const struct cpumask *housekeeping_cpumask_rcu(enum hk_type type)
+{
+       const struct cpumask *mask = NULL;
+
+       if (static_branch_unlikely(&housekeeping_overridden)) {
+               if (READ_ONCE(housekeeping.flags) & BIT(type))
+                       mask = rcu_dereference(housekeeping.cpumasks[type]);
+       }
+       if (!mask)
+               mask = cpu_possible_mask;
+       return mask;
+}
+EXPORT_SYMBOL_GPL(housekeeping_cpumask_rcu);
+
 int housekeeping_any_cpu(enum hk_type type)
 {
        int cpu;
 
        if (static_branch_unlikely(&housekeeping_overridden)) {
-               if (housekeeping.flags & BIT(type)) {
+               if (READ_ONCE(housekeeping.flags) & BIT(type)) {
                        cpu = 
sched_numa_find_closest(housekeeping_cpumask(type), smp_processor_id());
                        if (cpu < nr_cpu_ids)
                                return cpu;

-- 
2.43.0


Reply via email to