diff options
| author | James Morse <james.morse@arm.com> | 2019-03-19 17:39:31 +0000 |
|---|---|---|
| committer | James Morse <james.morse@arm.com> | 2021-11-09 17:56:14 +0000 |
| commit | 63dc771f72401f998123fca77456c2ef652f1fa6 (patch) | |
| tree | 6d10ca646252cdac8291a3cd30be4d795d3e0776 | |
| parent | 29a4ebaa5e6573f979111d361e741ba9e49451a7 (diff) | |
| download | linux-63dc771f72401f998123fca77456c2ef652f1fa6.tar.gz | |
x86/resctrl: Split arch and fs resctrl locks
resctrl has one mutex that is taken by the arch code, and the fs parts.
Lets split this up so we can't accidentally have conflicting dependencies
between architectures.
The arch and fs code interact via cpuhp where the arch code updates
the domain list. Create a new domain_list_lock for arch code updates
to the domain list.
It is now no-longer enough for resctrl to take the rdtgroup_mutex to
block changes to this list, use cpus_read_lock() for that. Taking
cpus_read_lock() in rdtgroup_kn_lock_live() covers most of these,
add lockdep_assert_cpus_held() in the cases where the
rdtgroup_kn_lock_live() call isn't obvious.
Our domain online/offline calls now need to take the rdtgroup_mutex
themselves.
Signed-off-by: James Morse <james.morse@arm.com>
| -rw-r--r-- | arch/x86/kernel/cpu/resctrl/core.c | 17 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/resctrl/ctrlmondata.c | 14 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/resctrl/monitor.c | 3 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/resctrl/pseudo_lock.c | 3 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/resctrl/rdtgroup.c | 38 |
5 files changed, 58 insertions, 17 deletions
diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c index 0ac611b3bc152..ae5d9e2d20b3b 100644 --- a/arch/x86/kernel/cpu/resctrl/core.c +++ b/arch/x86/kernel/cpu/resctrl/core.c @@ -25,8 +25,13 @@ #include <asm/resctrl.h> #include "internal.h" -/* Mutex to protect rdtgroup access. */ -DEFINE_MUTEX(rdtgroup_mutex); +/* + * rdt_domain structures are kfree()d when their last cpu goes offline, + * and allocated when the first cpu in a new domain comes online. + * The rdt_resource's domain list is updated when this happens. The domain + * list is protected by cpuhp as a rwlock, writers also take this mutex. + */ +DEFINE_MUTEX(domain_list_lock); /* * The cached resctrl_pqr_state is strictly per CPU and can never be @@ -586,11 +591,11 @@ static int resctrl_arch_online_cpu(unsigned int cpu) { struct rdt_resource *r; - mutex_lock(&rdtgroup_mutex); + mutex_lock(&domain_list_lock); for_each_capable_rdt_resource(r) domain_add_cpu(cpu, r); clear_closid_rmid(cpu); - mutex_unlock(&rdtgroup_mutex); + mutex_unlock(&domain_list_lock); return resctrl_online_cpu(cpu); } @@ -601,11 +606,11 @@ static int resctrl_arch_offline_cpu(unsigned int cpu) resctrl_offline_cpu(cpu); - mutex_lock(&rdtgroup_mutex); + mutex_lock(&domain_list_lock); for_each_capable_rdt_resource(r) domain_remove_cpu(cpu, r); clear_closid_rmid(cpu); - mutex_unlock(&rdtgroup_mutex); + mutex_unlock(&domain_list_lock); return 0; } diff --git a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c index fb15ad277de10..f10f7e88c8f08 100644 --- a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c +++ b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c @@ -227,6 +227,9 @@ static int parse_line(char *line, struct resctrl_schema *s, struct rdt_domain *d; unsigned long dom_id; + /* Walking r->domains, ensure it can't race with cpuhp */ + lockdep_assert_cpus_held(); + if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP && r->rid == RDT_RESOURCE_MBA) { rdt_last_cmd_puts("Cannot pseudo-lock MBA resource\n"); @@ -332,6 +335,9 @@ int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid) int cpu; u32 idx; + /* Walking r->domains, ensure it can't race with cpuhp */ + lockdep_assert_cpus_held(); + if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL)) return -ENOMEM; @@ -402,11 +408,9 @@ ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of, return -EINVAL; buf[nbytes - 1] = '\0'; - cpus_read_lock(); rdtgrp = rdtgroup_kn_lock_live(of->kn); if (!rdtgrp) { rdtgroup_kn_unlock(of->kn); - cpus_read_unlock(); return -ENOENT; } rdt_last_cmd_clear(); @@ -470,7 +474,6 @@ ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of, out: rdtgroup_kn_unlock(of->kn); - cpus_read_unlock(); return ret ?: nbytes; } @@ -490,6 +493,9 @@ static void show_doms(struct seq_file *s, struct resctrl_schema *schema, int clo bool sep = false; u32 ctrl_val; + /* Walking r->domains, ensure it can't race with cpuhp */ + lockdep_assert_cpus_held(); + seq_printf(s, "%*s:", max_name_width, schema->name); list_for_each_entry(dom, &r->domains, list) { if (sep) @@ -552,7 +558,7 @@ void mon_event_read(struct rmid_read *rr, struct rdt_resource *r, int evtid, int first) { /* When picking a cpu from cpu_mask, ensure it can't race with cpuhp */ - lockdep_assert_held(&rdtgroup_mutex); + lockdep_assert_cpus_held(); /* * setup the parameters to send to pass to mon_event_count() to read diff --git a/arch/x86/kernel/cpu/resctrl/monitor.c b/arch/x86/kernel/cpu/resctrl/monitor.c index 2dcb998aa7d46..eee76c80b83cd 100644 --- a/arch/x86/kernel/cpu/resctrl/monitor.c +++ b/arch/x86/kernel/cpu/resctrl/monitor.c @@ -409,6 +409,9 @@ static void add_rmid_to_limbo(struct rmid_entry *entry) u32 idx; int err; + /* Walking r->domains, ensure it can't race with cpuhp */ + lockdep_assert_cpus_held(); + idx = resctrl_arch_rmid_idx_encode(entry->closid, entry->rmid); arch_mon_ctx = resctrl_arch_mon_ctx_alloc(r, QOS_L3_OCCUP_EVENT_ID); diff --git a/arch/x86/kernel/cpu/resctrl/pseudo_lock.c b/arch/x86/kernel/cpu/resctrl/pseudo_lock.c index f54614ed36b33..a38a5683d87f7 100644 --- a/arch/x86/kernel/cpu/resctrl/pseudo_lock.c +++ b/arch/x86/kernel/cpu/resctrl/pseudo_lock.c @@ -828,6 +828,9 @@ bool rdtgroup_pseudo_locked_in_hierarchy(struct rdt_domain *d) struct rdt_domain *d_i; bool ret = false; + /* Walking r->domains, ensure it can't race with cpuhp */ + lockdep_assert_cpus_held(); + if (!zalloc_cpumask_var(&cpu_with_psl, GFP_KERNEL)) return true; diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c index b3fe0475d323e..23ce5feace823 100644 --- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c +++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c @@ -35,6 +35,10 @@ 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); @@ -939,6 +943,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) { @@ -999,6 +1004,8 @@ static int rdt_bit_usage_show(struct kernfs_open_file *of, } seq_putc(seq, '\n'); mutex_unlock(&rdtgroup_mutex); + cpus_read_unlock(); + return 0; } @@ -1238,6 +1245,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) @@ -1871,6 +1881,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) @@ -2093,6 +2106,7 @@ struct rdtgroup *rdtgroup_kn_lock_live(struct kernfs_node *kn) atomic_inc(&rdtgrp->waitcount); kernfs_break_active_protection(kn); + cpus_read_lock(); mutex_lock(&rdtgroup_mutex); /* Was this group deleted while we waited? */ @@ -2110,6 +2124,7 @@ void rdtgroup_kn_unlock(struct kernfs_node *kn) return; mutex_unlock(&rdtgroup_mutex); + cpus_read_unlock(); if (atomic_dec_and_test(&rdtgrp->waitcount) && (rdtgrp->flags & RDT_DELETED)) { @@ -2405,6 +2420,9 @@ static int reset_all_ctrls(struct rdt_resource *r) struct rdt_domain *d; int i, cpu; + /* Walking r->domains, ensure it can't race with cpuhp */ + lockdep_assert_cpus_held(); + if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL)) return -ENOMEM; @@ -2685,6 +2703,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) @@ -3369,11 +3390,10 @@ 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); - if (!r->mon_capable) return; + mutex_lock(&rdtgroup_mutex); /* * If resctrl is mounted, remove all the * per domain monitor data directories. @@ -3400,6 +3420,8 @@ void resctrl_offline_domain(struct rdt_resource *r, struct rdt_domain *d) mba_sc_domain_destroy(r, d); domain_destroy_mon_state(d); + + mutex_unlock(&rdtgroup_mutex); } static int domain_setup_mon_state(struct rdt_resource *r, struct rdt_domain *d) @@ -3437,20 +3459,19 @@ int resctrl_online_domain(struct rdt_resource *r, struct rdt_domain *d) { int err; - lockdep_assert_held(&rdtgroup_mutex); - if (!r->mon_capable) return 0; + mutex_lock(&rdtgroup_mutex); err = domain_setup_mon_state(r, d); if (err) - return err; + goto out_unlock; if (is_mba_sc(r)) { err = mba_sc_domain_allocate(r, d); if (err) { domain_destroy_mon_state(d); - return err; + goto out_unlock; } } @@ -3465,7 +3486,10 @@ 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; } int resctrl_online_cpu(unsigned int cpu) |
