Message ID | 20250205031425.67265-2-cuiyunhui@bytedance.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | Fix dwc_pcie pmu driver issues | expand |
在 2025/2/5 11:14, Yunhui Cui 写道: > for_each_pci_dev increments pdev refcount. Call pci_dev_put after access > to decrement it. > > Signed-off-by: Yunhui Cui <cuiyunhui@bytedance.com> > --- > drivers/perf/dwc_pcie_pmu.c | 42 ++++++++++++++++++++++++++----------- > 1 file changed, 30 insertions(+), 12 deletions(-) > > diff --git a/drivers/perf/dwc_pcie_pmu.c b/drivers/perf/dwc_pcie_pmu.c > index cccecae9823f..4ac53167d7ab 100644 > --- a/drivers/perf/dwc_pcie_pmu.c > +++ b/drivers/perf/dwc_pcie_pmu.c > @@ -553,6 +553,7 @@ static u16 dwc_pcie_des_cap(struct pci_dev *pdev) > > static void dwc_pcie_unregister_dev(struct dwc_pcie_dev_info *dev_info) > { > + pci_dev_put(dev_info->pdev); > platform_device_unregister(dev_info->plat_dev); > list_del(&dev_info->dev_node); > kfree(dev_info); > @@ -572,8 +573,10 @@ static int dwc_pcie_register_dev(struct pci_dev *pdev) > return PTR_ERR(plat_dev); > > dev_info = kzalloc(sizeof(*dev_info), GFP_KERNEL); > - if (!dev_info) > + if (!dev_info) { > + platform_device_unregister(plat_dev); > return -ENOMEM; > + } > > /* Cache platform device to handle pci device hotplug */ > dev_info->plat_dev = plat_dev; > @@ -594,8 +597,11 @@ static int dwc_pcie_pmu_notifier(struct notifier_block *nb, > case BUS_NOTIFY_ADD_DEVICE: > if (!dwc_pcie_des_cap(pdev)) > return NOTIFY_DONE; > - if (dwc_pcie_register_dev(pdev)) > + pci_dev_get(pdev); > + if (dwc_pcie_register_dev(pdev)) { > + pci_dev_put(pdev); > return NOTIFY_BAD; > + } > break; > case BUS_NOTIFY_DEL_DEVICE: > dev_info = dwc_pcie_find_dev_info(pdev); > @@ -730,20 +736,29 @@ static struct platform_driver dwc_pcie_pmu_driver = { > .driver = {.name = "dwc_pcie_pmu",}, > }; > > +static void dwc_pcie_cleanup_devices(void) > +{ > + struct dwc_pcie_dev_info *dev_info, *tmp; > + > + list_for_each_entry_safe(dev_info, tmp, &dwc_pcie_dev_info_head, dev_node) { > + dwc_pcie_unregister_dev(dev_info); > + } > +} > + > static int __init dwc_pcie_pmu_init(void) > { > struct pci_dev *pdev = NULL; > int ret; > > for_each_pci_dev(pdev) { > - if (!dwc_pcie_des_cap(pdev)) > + if (!dwc_pcie_des_cap(pdev)) { > + pci_dev_put(pdev); If the pdev has no RAS cap, we do not need to put the device. > The reference count for @from is > always decremented if it is not %NULL. Please see comments from pci_get_device() for more details. Shuai
Hi Shuai, On Fri, Feb 7, 2025 at 10:20 AM Shuai Xue <xueshuai@linux.alibaba.com> wrote: > > > > 在 2025/2/5 11:14, Yunhui Cui 写道: > > for_each_pci_dev increments pdev refcount. Call pci_dev_put after access > > to decrement it. > > > > Signed-off-by: Yunhui Cui <cuiyunhui@bytedance.com> > > --- > > drivers/perf/dwc_pcie_pmu.c | 42 ++++++++++++++++++++++++++----------- > > 1 file changed, 30 insertions(+), 12 deletions(-) > > > > diff --git a/drivers/perf/dwc_pcie_pmu.c b/drivers/perf/dwc_pcie_pmu.c > > index cccecae9823f..4ac53167d7ab 100644 > > --- a/drivers/perf/dwc_pcie_pmu.c > > +++ b/drivers/perf/dwc_pcie_pmu.c > > @@ -553,6 +553,7 @@ static u16 dwc_pcie_des_cap(struct pci_dev *pdev) > > > > static void dwc_pcie_unregister_dev(struct dwc_pcie_dev_info *dev_info) > > { > > + pci_dev_put(dev_info->pdev); > > platform_device_unregister(dev_info->plat_dev); > > list_del(&dev_info->dev_node); > > kfree(dev_info); > > @@ -572,8 +573,10 @@ static int dwc_pcie_register_dev(struct pci_dev *pdev) > > return PTR_ERR(plat_dev); > > > > dev_info = kzalloc(sizeof(*dev_info), GFP_KERNEL); > > - if (!dev_info) > > + if (!dev_info) { > > + platform_device_unregister(plat_dev); > > return -ENOMEM; > > + } > > > > /* Cache platform device to handle pci device hotplug */ > > dev_info->plat_dev = plat_dev; > > @@ -594,8 +597,11 @@ static int dwc_pcie_pmu_notifier(struct notifier_block *nb, > > case BUS_NOTIFY_ADD_DEVICE: > > if (!dwc_pcie_des_cap(pdev)) > > return NOTIFY_DONE; > > - if (dwc_pcie_register_dev(pdev)) > > + pci_dev_get(pdev); > > + if (dwc_pcie_register_dev(pdev)) { > > + pci_dev_put(pdev); > > return NOTIFY_BAD; > > + } > > break; > > case BUS_NOTIFY_DEL_DEVICE: > > dev_info = dwc_pcie_find_dev_info(pdev); > > @@ -730,20 +736,29 @@ static struct platform_driver dwc_pcie_pmu_driver = { > > .driver = {.name = "dwc_pcie_pmu",}, > > }; > > > > +static void dwc_pcie_cleanup_devices(void) > > +{ > > + struct dwc_pcie_dev_info *dev_info, *tmp; > > + > > + list_for_each_entry_safe(dev_info, tmp, &dwc_pcie_dev_info_head, dev_node) { > > + dwc_pcie_unregister_dev(dev_info); > > + } > > +} > > + > > static int __init dwc_pcie_pmu_init(void) > > { > > struct pci_dev *pdev = NULL; > > int ret; > > > > for_each_pci_dev(pdev) { > > - if (!dwc_pcie_des_cap(pdev)) > > + if (!dwc_pcie_des_cap(pdev)) { > > + pci_dev_put(pdev); > > If the pdev has no RAS cap, we do not need to put the device. > > > The reference count for @from is > > always decremented if it is not %NULL. > > Please see comments from pci_get_device() for more details. Oh, yes. If that's the case, I'll update to v3. > Shuai > Thanks, Yunhui
diff --git a/drivers/perf/dwc_pcie_pmu.c b/drivers/perf/dwc_pcie_pmu.c index cccecae9823f..4ac53167d7ab 100644 --- a/drivers/perf/dwc_pcie_pmu.c +++ b/drivers/perf/dwc_pcie_pmu.c @@ -553,6 +553,7 @@ static u16 dwc_pcie_des_cap(struct pci_dev *pdev) static void dwc_pcie_unregister_dev(struct dwc_pcie_dev_info *dev_info) { + pci_dev_put(dev_info->pdev); platform_device_unregister(dev_info->plat_dev); list_del(&dev_info->dev_node); kfree(dev_info); @@ -572,8 +573,10 @@ static int dwc_pcie_register_dev(struct pci_dev *pdev) return PTR_ERR(plat_dev); dev_info = kzalloc(sizeof(*dev_info), GFP_KERNEL); - if (!dev_info) + if (!dev_info) { + platform_device_unregister(plat_dev); return -ENOMEM; + } /* Cache platform device to handle pci device hotplug */ dev_info->plat_dev = plat_dev; @@ -594,8 +597,11 @@ static int dwc_pcie_pmu_notifier(struct notifier_block *nb, case BUS_NOTIFY_ADD_DEVICE: if (!dwc_pcie_des_cap(pdev)) return NOTIFY_DONE; - if (dwc_pcie_register_dev(pdev)) + pci_dev_get(pdev); + if (dwc_pcie_register_dev(pdev)) { + pci_dev_put(pdev); return NOTIFY_BAD; + } break; case BUS_NOTIFY_DEL_DEVICE: dev_info = dwc_pcie_find_dev_info(pdev); @@ -730,20 +736,29 @@ static struct platform_driver dwc_pcie_pmu_driver = { .driver = {.name = "dwc_pcie_pmu",}, }; +static void dwc_pcie_cleanup_devices(void) +{ + struct dwc_pcie_dev_info *dev_info, *tmp; + + list_for_each_entry_safe(dev_info, tmp, &dwc_pcie_dev_info_head, dev_node) { + dwc_pcie_unregister_dev(dev_info); + } +} + static int __init dwc_pcie_pmu_init(void) { struct pci_dev *pdev = NULL; int ret; for_each_pci_dev(pdev) { - if (!dwc_pcie_des_cap(pdev)) + if (!dwc_pcie_des_cap(pdev)) { + pci_dev_put(pdev); continue; + } ret = dwc_pcie_register_dev(pdev); - if (ret) { - pci_dev_put(pdev); - return ret; - } + if (ret) + goto err_cleanup; } ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, @@ -751,24 +766,27 @@ static int __init dwc_pcie_pmu_init(void) dwc_pcie_pmu_online_cpu, dwc_pcie_pmu_offline_cpu); if (ret < 0) - return ret; + goto err_cleanup; dwc_pcie_pmu_hp_state = ret; ret = platform_driver_register(&dwc_pcie_pmu_driver); if (ret) - goto platform_driver_register_err; + goto err_remove_cpuhp; ret = bus_register_notifier(&pci_bus_type, &dwc_pcie_pmu_nb); if (ret) - goto platform_driver_register_err; + goto err_unregister_driver; notify = true; return 0; -platform_driver_register_err: +err_unregister_driver: + platform_driver_unregister(&dwc_pcie_pmu_driver); +err_remove_cpuhp: cpuhp_remove_multi_state(dwc_pcie_pmu_hp_state); - +err_cleanup: + dwc_pcie_cleanup_devices(); return ret; }
for_each_pci_dev increments pdev refcount. Call pci_dev_put after access to decrement it. Signed-off-by: Yunhui Cui <cuiyunhui@bytedance.com> --- drivers/perf/dwc_pcie_pmu.c | 42 ++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 12 deletions(-)