Merge tag 'x86-asm-2024-03-11' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
[linux-2.6-block.git] / arch / x86 / kernel / cpu / resctrl / rdtgroup.c
index 38d3b19a3aca1ff8e7c11fd41da2637058f07658..011e17efb1a66e5b003fee07b53c13633f9f0f58 100644 (file)
 DEFINE_STATIC_KEY_FALSE(rdt_enable_key);
 DEFINE_STATIC_KEY_FALSE(rdt_mon_enable_key);
 DEFINE_STATIC_KEY_FALSE(rdt_alloc_enable_key);
+
+/* Mutex to protect rdtgroup access. */
+DEFINE_MUTEX(rdtgroup_mutex);
+
 static struct kernfs_root *rdt_root;
 struct rdtgroup rdtgroup_default;
 LIST_HEAD(rdt_all_groups);
@@ -1014,6 +1018,7 @@ static int rdt_bit_usage_show(struct kernfs_open_file *of,
        bool sep = false;
        u32 ctrl_val;
 
+       cpus_read_lock();
        mutex_lock(&rdtgroup_mutex);
        hw_shareable = r->cache.shareable_bits;
        list_for_each_entry(dom, &r->domains, list) {
@@ -1074,6 +1079,7 @@ static int rdt_bit_usage_show(struct kernfs_open_file *of,
        }
        seq_putc(seq, '\n');
        mutex_unlock(&rdtgroup_mutex);
+       cpus_read_unlock();
        return 0;
 }
 
@@ -1329,6 +1335,9 @@ static bool rdtgroup_mode_test_exclusive(struct rdtgroup *rdtgrp)
        struct rdt_domain *d;
        u32 ctrl;
 
+       /* Walking r->domains, ensure it can't race with cpuhp */
+       lockdep_assert_cpus_held();
+
        list_for_each_entry(s, &resctrl_schema_all, list) {
                r = s->res;
                if (r->rid == RDT_RESOURCE_MBA || r->rid == RDT_RESOURCE_SMBA)
@@ -1593,6 +1602,7 @@ static int mbm_config_show(struct seq_file *s, struct rdt_resource *r, u32 evtid
        struct rdt_domain *dom;
        bool sep = false;
 
+       cpus_read_lock();
        mutex_lock(&rdtgroup_mutex);
 
        list_for_each_entry(dom, &r->domains, list) {
@@ -1609,6 +1619,7 @@ static int mbm_config_show(struct seq_file *s, struct rdt_resource *r, u32 evtid
        seq_puts(s, "\n");
 
        mutex_unlock(&rdtgroup_mutex);
+       cpus_read_unlock();
 
        return 0;
 }
@@ -1690,6 +1701,9 @@ static int mon_config_write(struct rdt_resource *r, char *tok, u32 evtid)
        unsigned long dom_id, val;
        struct rdt_domain *d;
 
+       /* Walking r->domains, ensure it can't race with cpuhp */
+       lockdep_assert_cpus_held();
+
 next:
        if (!tok || tok[0] == '\0')
                return 0;
@@ -1736,6 +1750,7 @@ static ssize_t mbm_total_bytes_config_write(struct kernfs_open_file *of,
        if (nbytes == 0 || buf[nbytes - 1] != '\n')
                return -EINVAL;
 
+       cpus_read_lock();
        mutex_lock(&rdtgroup_mutex);
 
        rdt_last_cmd_clear();
@@ -1745,6 +1760,7 @@ static ssize_t mbm_total_bytes_config_write(struct kernfs_open_file *of,
        ret = mon_config_write(r, buf, QOS_L3_MBM_TOTAL_EVENT_ID);
 
        mutex_unlock(&rdtgroup_mutex);
+       cpus_read_unlock();
 
        return ret ?: nbytes;
 }
@@ -1760,6 +1776,7 @@ static ssize_t mbm_local_bytes_config_write(struct kernfs_open_file *of,
        if (nbytes == 0 || buf[nbytes - 1] != '\n')
                return -EINVAL;
 
+       cpus_read_lock();
        mutex_lock(&rdtgroup_mutex);
 
        rdt_last_cmd_clear();
@@ -1769,6 +1786,7 @@ static ssize_t mbm_local_bytes_config_write(struct kernfs_open_file *of,
        ret = mon_config_write(r, buf, QOS_L3_MBM_LOCAL_EVENT_ID);
 
        mutex_unlock(&rdtgroup_mutex);
+       cpus_read_unlock();
 
        return ret ?: nbytes;
 }
@@ -2245,6 +2263,9 @@ static int set_cache_qos_cfg(int level, bool enable)
        struct rdt_domain *d;
        int cpu;
 
+       /* Walking r->domains, ensure it can't race with cpuhp */
+       lockdep_assert_cpus_held();
+
        if (level == RDT_RESOURCE_L3)
                update = l3_qos_cfg_update;
        else if (level == RDT_RESOURCE_L2)
@@ -2444,6 +2465,7 @@ struct rdtgroup *rdtgroup_kn_lock_live(struct kernfs_node *kn)
 
        rdtgroup_kn_get(rdtgrp, kn);
 
+       cpus_read_lock();
        mutex_lock(&rdtgroup_mutex);
 
        /* Was this group deleted while we waited? */
@@ -2461,6 +2483,8 @@ void rdtgroup_kn_unlock(struct kernfs_node *kn)
                return;
 
        mutex_unlock(&rdtgroup_mutex);
+       cpus_read_unlock();
+
        rdtgroup_kn_put(rdtgrp, kn);
 }
 
@@ -2678,7 +2702,8 @@ static int rdt_get_tree(struct fs_context *fc)
        if (is_mbm_enabled()) {
                r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;
                list_for_each_entry(dom, &r->domains, list)
-                       mbm_setup_overflow_handler(dom, MBM_OVERFLOW_INTERVAL);
+                       mbm_setup_overflow_handler(dom, MBM_OVERFLOW_INTERVAL,
+                                                  RESCTRL_PICK_ANY_CPU);
        }
 
        goto out;
@@ -2792,6 +2817,9 @@ static int reset_all_ctrls(struct rdt_resource *r)
        struct rdt_domain *d;
        int i;
 
+       /* Walking r->domains, ensure it can't race with cpuhp */
+       lockdep_assert_cpus_held();
+
        if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL))
                return -ENOMEM;
 
@@ -3076,6 +3104,9 @@ static int mkdir_mondata_subdir_alldom(struct kernfs_node *parent_kn,
        struct rdt_domain *dom;
        int ret;
 
+       /* Walking r->domains, ensure it can't race with cpuhp */
+       lockdep_assert_cpus_held();
+
        list_for_each_entry(dom, &r->domains, list) {
                ret = mkdir_mondata_subdir(parent_kn, dom, r, prgrp);
                if (ret)
@@ -3906,13 +3937,13 @@ static void domain_destroy_mon_state(struct rdt_domain *d)
 
 void resctrl_offline_domain(struct rdt_resource *r, struct rdt_domain *d)
 {
-       lockdep_assert_held(&rdtgroup_mutex);
+       mutex_lock(&rdtgroup_mutex);
 
        if (supports_mba_mbps() && r->rid == RDT_RESOURCE_MBA)
                mba_sc_domain_destroy(r, d);
 
        if (!r->mon_capable)
-               return;
+               goto out_unlock;
 
        /*
         * If resctrl is mounted, remove all the
@@ -3937,6 +3968,9 @@ void resctrl_offline_domain(struct rdt_resource *r, struct rdt_domain *d)
        }
 
        domain_destroy_mon_state(d);
+
+out_unlock:
+       mutex_unlock(&rdtgroup_mutex);
 }
 
 static int domain_setup_mon_state(struct rdt_resource *r, struct rdt_domain *d)
@@ -3972,24 +4006,27 @@ static int domain_setup_mon_state(struct rdt_resource *r, struct rdt_domain *d)
 
 int resctrl_online_domain(struct rdt_resource *r, struct rdt_domain *d)
 {
-       int err;
+       int err = 0;
 
-       lockdep_assert_held(&rdtgroup_mutex);
+       mutex_lock(&rdtgroup_mutex);
 
-       if (supports_mba_mbps() && r->rid == RDT_RESOURCE_MBA)
+       if (supports_mba_mbps() && r->rid == RDT_RESOURCE_MBA) {
                /* RDT_RESOURCE_MBA is never mon_capable */
-               return mba_sc_domain_allocate(r, d);
+               err = mba_sc_domain_allocate(r, d);
+               goto out_unlock;
+       }
 
        if (!r->mon_capable)
-               return 0;
+               goto out_unlock;
 
        err = domain_setup_mon_state(r, d);
        if (err)
-               return err;
+               goto out_unlock;
 
        if (is_mbm_enabled()) {
                INIT_DELAYED_WORK(&d->mbm_over, mbm_handle_overflow);
-               mbm_setup_overflow_handler(d, MBM_OVERFLOW_INTERVAL);
+               mbm_setup_overflow_handler(d, MBM_OVERFLOW_INTERVAL,
+                                          RESCTRL_PICK_ANY_CPU);
        }
 
        if (is_llc_occupancy_enabled())
@@ -4004,15 +4041,62 @@ int resctrl_online_domain(struct rdt_resource *r, struct rdt_domain *d)
        if (resctrl_mounted && resctrl_arch_mon_capable())
                mkdir_mondata_subdir_allrdtgrp(r, d);
 
-       return 0;
+out_unlock:
+       mutex_unlock(&rdtgroup_mutex);
+
+       return err;
 }
 
 void resctrl_online_cpu(unsigned int cpu)
 {
-       lockdep_assert_held(&rdtgroup_mutex);
-
+       mutex_lock(&rdtgroup_mutex);
        /* The CPU is set in default rdtgroup after online. */
        cpumask_set_cpu(cpu, &rdtgroup_default.cpu_mask);
+       mutex_unlock(&rdtgroup_mutex);
+}
+
+static void clear_childcpus(struct rdtgroup *r, unsigned int cpu)
+{
+       struct rdtgroup *cr;
+
+       list_for_each_entry(cr, &r->mon.crdtgrp_list, mon.crdtgrp_list) {
+               if (cpumask_test_and_clear_cpu(cpu, &cr->cpu_mask))
+                       break;
+       }
+}
+
+void resctrl_offline_cpu(unsigned int cpu)
+{
+       struct rdt_resource *l3 = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;
+       struct rdtgroup *rdtgrp;
+       struct rdt_domain *d;
+
+       mutex_lock(&rdtgroup_mutex);
+       list_for_each_entry(rdtgrp, &rdt_all_groups, rdtgroup_list) {
+               if (cpumask_test_and_clear_cpu(cpu, &rdtgrp->cpu_mask)) {
+                       clear_childcpus(rdtgrp, cpu);
+                       break;
+               }
+       }
+
+       if (!l3->mon_capable)
+               goto out_unlock;
+
+       d = get_domain_from_cpu(cpu, l3);
+       if (d) {
+               if (is_mbm_enabled() && cpu == d->mbm_work_cpu) {
+                       cancel_delayed_work(&d->mbm_over);
+                       mbm_setup_overflow_handler(d, 0, cpu);
+               }
+               if (is_llc_occupancy_enabled() && cpu == d->cqm_work_cpu &&
+                   has_busy_rmid(d)) {
+                       cancel_delayed_work(&d->cqm_limbo);
+                       cqm_setup_limbo_handler(d, 0, cpu);
+               }
+       }
+
+out_unlock:
+       mutex_unlock(&rdtgroup_mutex);
 }
 
 /*