From 2bcc8e5f0bd7fcf164fee00d01ab18771dddeb57 Mon Sep 17 00:00:00 2001 From: Naushir Patuck Date: Mon, 14 Sep 2026 14:45:44 +0100 Subject: [PATCH 1/3] media: rp1-cfe: Release the vb2 queue when unregistering a node cfe_register_node() initialises the node vb2 queue but cfe_unregister_nodes() never released it, causing a memory leak. Release the queue after unregistering the video device so that the driver can be removed, and nodes can later be re-registered without leaking memory. Signed-off-by: Naushir Patuck --- drivers/media/platform/raspberrypi/rp1_cfe/cfe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c index 295fb8ad4281af..2ecbd6441bd504 100644 --- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c +++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c @@ -2038,6 +2038,7 @@ static void cfe_unregister_nodes(struct cfe_device *cfe) if (check_state(cfe, NODE_REGISTERED, i)) { clear_state(cfe, NODE_REGISTERED, i); video_unregister_device(&node->video_dev); + vb2_queue_release(&node->buffer_queue); } } } From 5dcea631207436738b9652239bbe7e52b5a4f8ec Mon Sep 17 00:00:00 2001 From: Naushir Patuck Date: Mon, 14 Sep 2026 15:20:31 +0100 Subject: [PATCH 2/3] media: rp1-cfe: Reset the video_device before re-registering it After a node is unregistered its embedded video_device still carries the released struct device and kobject state. Re-registering it triggered a "tried to init an initialized object" and use-after-free situation. Reset the video_device before registering it so that the node can be re-registered after the source subdev is rebound. Signed-off-by: Naushir Patuck --- drivers/media/platform/raspberrypi/rp1_cfe/cfe.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c index 2ecbd6441bd504..6b1160e2bcb634 100644 --- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c +++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c @@ -1915,6 +1915,13 @@ static int cfe_register_node(struct cfe_device *cfe, int id) struct cfe_node *node = &cfe->node[id]; int ret; + /* + * The node may be re-registered after the source subdev has been + * unbound and rebound. The embedded video_device must be reset before + * being re-registered. + */ + memset(&node->video_dev, 0, sizeof(node->video_dev)); + node->cfe = cfe; node->id = id; From ded793e884c1147d32a4025c1f4822cdd75852f4 Mon Sep 17 00:00:00 2001 From: Naushir Patuck Date: Mon, 14 Sep 2026 14:45:45 +0100 Subject: [PATCH 3/3] media: rp1-cfe: Add an unbind callback to tear down the graph Rebinding or reloading the source sensor driver caused the notifier .complete() callback to run a second time and register duplicate video device entities and links on the media device. This would hit a BUG in media_gobj_create(). Add an .unbind() callback that unregisters the video nodes, removes the CSI2 and FE links and clears the source pointer, so that the graph is rebuilt from scratch on the next .complete(). Tested on Pi 5 with an IMX219 using: echo 11-0010 | sudo tee /sys/bus/i2c/drivers/imx219/unbind echo 11-0010 | sudo tee /sys/bus/i2c/drivers/imx219/bind echo 11-0010 | sudo tee /sys/bus/i2c/drivers/imx219/unbind sudo rmmod imx219 sudo modprobe imx219 Signed-off-by: Naushir Patuck --- .../media/platform/raspberrypi/rp1_cfe/cfe.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c index 6b1160e2bcb634..6bda6515714fd1 100644 --- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c +++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c @@ -2176,6 +2176,22 @@ static int cfe_async_bound(struct v4l2_async_notifier *notifier, return 0; } +static void cfe_async_unbind(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_connection *asd) +{ + struct cfe_device *cfe = to_cfe_device(notifier->v4l2_dev); + + if (cfe->sensor != subdev) + return; + + cfe_unregister_nodes(cfe); + media_entity_remove_links(&cfe->csi2.sd.entity); + media_entity_remove_links(&cfe->fe.sd.entity); + + cfe->sensor = NULL; +} + static int cfe_async_complete(struct v4l2_async_notifier *notifier) { struct cfe_device *cfe = to_cfe_device(notifier->v4l2_dev); @@ -2185,6 +2201,7 @@ static int cfe_async_complete(struct v4l2_async_notifier *notifier) static const struct v4l2_async_notifier_operations cfe_async_ops = { .bound = cfe_async_bound, + .unbind = cfe_async_unbind, .complete = cfe_async_complete, };