On Thu, Oct 20, 2016 at 10:58:03AM +0200, Jiri Olsa wrote: > @@ -8869,11 +8869,15 @@ void perf_pmu_unregister(struct pmu *pmu) > free_percpu(pmu->pmu_disable_count); > if (pmu->type >= PERF_TYPE_MAX) > idr_remove(&pmu_idr, pmu->type); > - if (pmu->nr_addr_filters) > - device_remove_file(pmu->dev, &dev_attr_nr_addr_filters); > - device_del(pmu->dev); > - put_device(pmu->dev); > + mutex_lock(&pmus_lock); > + if (pmu_bus_running) { > + if (pmu->nr_addr_filters) > + device_remove_file(pmu->dev, &dev_attr_nr_addr_filters); > + device_del(pmu->dev); > + put_device(pmu->dev); > + } > free_pmu_context(pmu); > + mutex_unlock(&pmus_lock); > } > EXPORT_SYMBOL_GPL(perf_pmu_unregister);
I think that is still racy.. unregister: sysfs_init: mutex_lock(&pmus_lock); list_del_rcu(&pmu->entry); mutex_unlock(&pmus_lock); synchronize_*rcu(); mutex_lock(&pmus_lock); list_for_each_entry(pmu, &pmus, entry) { /* add device muck */ /* will _NOT_ see our PMU */ } pmus_bus_running = 1; mutex_unlock(&pmus_lock); mutex_lock(&pmus_lock); if (pmu_bus_running) { device_del() /* OOPS */ What you want is to read pmu_bus_running in the same pmus_lock section as we do the list_del, and then use that local copy later.