Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'perf-urgent-2025-03-07' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull perf event fixes from Ingo Molnar:
"Fix a race between PMU registration and event creation, and fix
pmus_lock vs. pmus_srcu lock ordering"

* tag 'perf-urgent-2025-03-07' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
perf/core: Fix perf_pmu_register() vs. perf_init_event()
perf/core: Fix pmus_lock vs. pmus_srcu ordering

+28 -4
+28 -4
kernel/events/core.c
··· 11830 11830 static struct lock_class_key cpuctx_mutex; 11831 11831 static struct lock_class_key cpuctx_lock; 11832 11832 11833 + static bool idr_cmpxchg(struct idr *idr, unsigned long id, void *old, void *new) 11834 + { 11835 + void *tmp, *val = idr_find(idr, id); 11836 + 11837 + if (val != old) 11838 + return false; 11839 + 11840 + tmp = idr_replace(idr, new, id); 11841 + if (IS_ERR(tmp)) 11842 + return false; 11843 + 11844 + WARN_ON_ONCE(tmp != val); 11845 + return true; 11846 + } 11847 + 11833 11848 int perf_pmu_register(struct pmu *pmu, const char *name, int type) 11834 11849 { 11835 11850 int cpu, ret, max = PERF_TYPE_MAX; ··· 11871 11856 if (type >= 0) 11872 11857 max = type; 11873 11858 11874 - ret = idr_alloc(&pmu_idr, pmu, max, 0, GFP_KERNEL); 11859 + ret = idr_alloc(&pmu_idr, NULL, max, 0, GFP_KERNEL); 11875 11860 if (ret < 0) 11876 11861 goto free_pdc; 11877 11862 ··· 11879 11864 11880 11865 type = ret; 11881 11866 pmu->type = type; 11867 + atomic_set(&pmu->exclusive_cnt, 0); 11882 11868 11883 11869 if (pmu_bus_running && !pmu->dev) { 11884 11870 ret = pmu_dev_alloc(pmu); ··· 11928 11912 if (!pmu->event_idx) 11929 11913 pmu->event_idx = perf_event_idx_default; 11930 11914 11915 + /* 11916 + * Now that the PMU is complete, make it visible to perf_try_init_event(). 11917 + */ 11918 + if (!idr_cmpxchg(&pmu_idr, pmu->type, NULL, pmu)) 11919 + goto free_context; 11931 11920 list_add_rcu(&pmu->entry, &pmus); 11932 - atomic_set(&pmu->exclusive_cnt, 0); 11921 + 11933 11922 ret = 0; 11934 11923 unlock: 11935 11924 mutex_unlock(&pmus_lock); 11936 11925 11937 11926 return ret; 11927 + 11928 + free_context: 11929 + free_percpu(pmu->cpu_pmu_context); 11938 11930 11939 11931 free_dev: 11940 11932 if (pmu->dev && pmu->dev != PMU_NULL_DEV) { ··· 11963 11939 { 11964 11940 mutex_lock(&pmus_lock); 11965 11941 list_del_rcu(&pmu->entry); 11942 + idr_remove(&pmu_idr, pmu->type); 11943 + mutex_unlock(&pmus_lock); 11966 11944 11967 11945 /* 11968 11946 * We dereference the pmu list under both SRCU and regular RCU, so ··· 11974 11948 synchronize_rcu(); 11975 11949 11976 11950 free_percpu(pmu->pmu_disable_count); 11977 - idr_remove(&pmu_idr, pmu->type); 11978 11951 if (pmu_bus_running && pmu->dev && pmu->dev != PMU_NULL_DEV) { 11979 11952 if (pmu->nr_addr_filters) 11980 11953 device_remove_file(pmu->dev, &dev_attr_nr_addr_filters); ··· 11981 11956 put_device(pmu->dev); 11982 11957 } 11983 11958 free_pmu_context(pmu); 11984 - mutex_unlock(&pmus_lock); 11985 11959 } 11986 11960 EXPORT_SYMBOL_GPL(perf_pmu_unregister); 11987 11961