drivers/gpu/drm/mediatek/mtk_drm_drv.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-)
Using device_find_child() and of_find_device_by_node() to locate
devices could cause an imbalance in the device's reference count.
device_find_child() and of_find_device_by_node() both call
get_device() to increment the reference count of the found device
before returning the pointer. In mtk_drm_get_all_drm_priv(), these
references are never released through put_device(), resulting in
permanent reference count increments. Additionally, the
for_each_child_of_node() iterator fails to release node references in
all code paths. This leaks device node references when loop
termination occurs before reaching MAX_CRTC. These reference count
leaks may prevent device/node resources from being properly released
during driver unbind operations.
As comment of device_find_child() says, 'NOTE: you will need to drop
the reference with put_device() after use'.
Found by code review.
Cc: stable@vger.kernel.org
Fixes: 1ef7ed48356c ("drm/mediatek: Modify mediatek-drm for mt8195 multi mmsys support")
Signed-off-by: Ma Ke <make24@iscas.ac.cn>
---
Changes in v2:
- added goto labels as suggestions.
---
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 21 ++++++++++++++-------
1 file changed, 14 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index d5e6bab36414..f8a817689e16 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -387,19 +387,19 @@ static bool mtk_drm_get_all_drm_priv(struct device *dev)
of_id = of_match_node(mtk_drm_of_ids, node);
if (!of_id)
- continue;
+ goto next_put_node;
pdev = of_find_device_by_node(node);
if (!pdev)
- continue;
+ goto next_put_node;
drm_dev = device_find_child(&pdev->dev, NULL, mtk_drm_match);
if (!drm_dev)
- continue;
+ goto next_put_device_pdev_dev;
temp_drm_priv = dev_get_drvdata(drm_dev);
if (!temp_drm_priv)
- continue;
+ goto next_put_device_drm_dev;
if (temp_drm_priv->data->main_len)
all_drm_priv[CRTC_MAIN] = temp_drm_priv;
@@ -411,10 +411,17 @@ static bool mtk_drm_get_all_drm_priv(struct device *dev)
if (temp_drm_priv->mtk_drm_bound)
cnt++;
- if (cnt == MAX_CRTC) {
- of_node_put(node);
+next_put_device_drm_dev:
+ put_device(drm_dev);
+
+next_put_device_pdev_dev:
+ put_device(&pdev->dev);
+
+next_put_node:
+ of_node_put(node);
+
+ if (cnt == MAX_CRTC)
break;
- }
}
if (drm_priv->data->mmsys_dev_num == cnt) {
--
2.25.1
Ma Ke <make24@iscas.ac.cn> 於 2025年8月12日 週二 下午3:19寫道: > > Using device_find_child() and of_find_device_by_node() to locate > devices could cause an imbalance in the device's reference count. > device_find_child() and of_find_device_by_node() both call > get_device() to increment the reference count of the found device > before returning the pointer. In mtk_drm_get_all_drm_priv(), these > references are never released through put_device(), resulting in > permanent reference count increments. Additionally, the > for_each_child_of_node() iterator fails to release node references in > all code paths. This leaks device node references when loop > termination occurs before reaching MAX_CRTC. These reference count > leaks may prevent device/node resources from being properly released > during driver unbind operations. > > As comment of device_find_child() says, 'NOTE: you will need to drop > the reference with put_device() after use'. > > Found by code review. Applied to mediatek-drm-fixes [1], thanks. [1] https://git.kernel.org/pub/scm/linux/kernel/git/chunkuang.hu/linux.git/log/?h=mediatek-drm-fixes Regards, Chun-Kuang. > > Cc: stable@vger.kernel.org > Fixes: 1ef7ed48356c ("drm/mediatek: Modify mediatek-drm for mt8195 multi mmsys support") > Signed-off-by: Ma Ke <make24@iscas.ac.cn> > --- > Changes in v2: > - added goto labels as suggestions. > --- > drivers/gpu/drm/mediatek/mtk_drm_drv.c | 21 ++++++++++++++------- > 1 file changed, 14 insertions(+), 7 deletions(-) > > diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c > index d5e6bab36414..f8a817689e16 100644 > --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c > +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c > @@ -387,19 +387,19 @@ static bool mtk_drm_get_all_drm_priv(struct device *dev) > > of_id = of_match_node(mtk_drm_of_ids, node); > if (!of_id) > - continue; > + goto next_put_node; > > pdev = of_find_device_by_node(node); > if (!pdev) > - continue; > + goto next_put_node; > > drm_dev = device_find_child(&pdev->dev, NULL, mtk_drm_match); > if (!drm_dev) > - continue; > + goto next_put_device_pdev_dev; > > temp_drm_priv = dev_get_drvdata(drm_dev); > if (!temp_drm_priv) > - continue; > + goto next_put_device_drm_dev; > > if (temp_drm_priv->data->main_len) > all_drm_priv[CRTC_MAIN] = temp_drm_priv; > @@ -411,10 +411,17 @@ static bool mtk_drm_get_all_drm_priv(struct device *dev) > if (temp_drm_priv->mtk_drm_bound) > cnt++; > > - if (cnt == MAX_CRTC) { > - of_node_put(node); > +next_put_device_drm_dev: > + put_device(drm_dev); > + > +next_put_device_pdev_dev: > + put_device(&pdev->dev); > + > +next_put_node: > + of_node_put(node); > + > + if (cnt == MAX_CRTC) > break; > - } > } > > if (drm_priv->data->mmsys_dev_num == cnt) { > -- > 2.25.1 >
On Tue, 2025-08-12 at 15:19 +0800, Ma Ke wrote: > External email : Please do not click links or open attachments until you have verified the sender or the content. > > > Using device_find_child() and of_find_device_by_node() to locate > devices could cause an imbalance in the device's reference count. > device_find_child() and of_find_device_by_node() both call > get_device() to increment the reference count of the found device > before returning the pointer. In mtk_drm_get_all_drm_priv(), these > references are never released through put_device(), resulting in > permanent reference count increments. Additionally, the > for_each_child_of_node() iterator fails to release node references in > all code paths. This leaks device node references when loop > termination occurs before reaching MAX_CRTC. These reference count > leaks may prevent device/node resources from being properly released > during driver unbind operations. > > As comment of device_find_child() says, 'NOTE: you will need to drop > the reference with put_device() after use'. > > Found by code review. Reviewed-by: CK Hu <ck.hu@mediatek.com> > > Cc: stable@vger.kernel.org > Fixes: 1ef7ed48356c ("drm/mediatek: Modify mediatek-drm for mt8195 multi mmsys support") > Signed-off-by: Ma Ke <make24@iscas.ac.cn> > --- > Changes in v2: > - added goto labels as suggestions. > --- > drivers/gpu/drm/mediatek/mtk_drm_drv.c | 21 ++++++++++++++------- > 1 file changed, 14 insertions(+), 7 deletions(-) > > diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c > index d5e6bab36414..f8a817689e16 100644 > --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c > +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c > @@ -387,19 +387,19 @@ static bool mtk_drm_get_all_drm_priv(struct device *dev) > > of_id = of_match_node(mtk_drm_of_ids, node); > if (!of_id) > - continue; > + goto next_put_node; > > pdev = of_find_device_by_node(node); > if (!pdev) > - continue; > + goto next_put_node; > > drm_dev = device_find_child(&pdev->dev, NULL, mtk_drm_match); > if (!drm_dev) > - continue; > + goto next_put_device_pdev_dev; > > temp_drm_priv = dev_get_drvdata(drm_dev); > if (!temp_drm_priv) > - continue; > + goto next_put_device_drm_dev; > > if (temp_drm_priv->data->main_len) > all_drm_priv[CRTC_MAIN] = temp_drm_priv; > @@ -411,10 +411,17 @@ static bool mtk_drm_get_all_drm_priv(struct device *dev) > if (temp_drm_priv->mtk_drm_bound) > cnt++; > > - if (cnt == MAX_CRTC) { > - of_node_put(node); > +next_put_device_drm_dev: > + put_device(drm_dev); > + > +next_put_device_pdev_dev: > + put_device(&pdev->dev); > + > +next_put_node: > + of_node_put(node); > + > + if (cnt == MAX_CRTC) > break; > - } > } > > if (drm_priv->data->mmsys_dev_num == cnt) { > -- > 2.25.1 >
© 2016 - 2025 Red Hat, Inc.