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.

Reply via email to