* [PATCHv2 0/6] media: em28xx: fix lifecycle issues
@ 2026-06-16 13:10 Hans Verkuil
2026-06-16 13:10 ` [PATCHv2 1/6] media: core: v4l2-async.c: unreg subdev if asc_list is empty Hans Verkuil
` (5 more replies)
0 siblings, 6 replies; 8+ messages in thread
From: Hans Verkuil @ 2026-06-16 13:10 UTC (permalink / raw)
To: linux-media; +Cc: Mauricio Faria de Oliveira, Sakari Ailus
The first patch fixes (I believe) a bug in v4l2-async that
was introduced back in 2013. Sakari, can you take a look at this?
The second patch switches the em28xx driver to use the v4l2_device
release callback, letting the v4l2 core do all the refcounting
until the last user is gone and it is safe to free all memory.
The third patch drops the 'users' counter and uses the internal
v4l2_fh counter instead. The fourth patch switches
video_unregister_device to vb2_video_unregister_device: this
ensures all streaming is stopped when the video device is unregistered.
The fifth patch fixes a use-after-freed, and the last patch correctly
gives the vb2 buffers back to the vb2 framework if start_streaming
fails.
This has all been tested on my em28xx device.
Regards,
Hans
Hans Verkuil (6):
media: core: v4l2-async.c: unreg subdev if asc_list is empty
media: em28xx: use v4l2_device release callback
media: em28xx: drop 'users' field
media: em28xx: use vb2_video_unregister_device
media: em28xx: dev_info->pr_info since dev has been freed
media: em28xx: requeue buffers if start_streaming fails
drivers/media/usb/em28xx/em28xx-cards.c | 2 +-
drivers/media/usb/em28xx/em28xx-video.c | 114 +++++++++++++++---------
drivers/media/usb/em28xx/em28xx.h | 2 -
drivers/media/v4l2-core/v4l2-async.c | 4 +-
4 files changed, 74 insertions(+), 48 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCHv2 1/6] media: core: v4l2-async.c: unreg subdev if asc_list is empty
2026-06-16 13:10 [PATCHv2 0/6] media: em28xx: fix lifecycle issues Hans Verkuil
@ 2026-06-16 13:10 ` Hans Verkuil
2026-06-16 15:15 ` Sakari Ailus
2026-06-16 13:10 ` [PATCHv2 2/6] media: em28xx: use v4l2_device release callback Hans Verkuil
` (4 subsequent siblings)
5 siblings, 1 reply; 8+ messages in thread
From: Hans Verkuil @ 2026-06-16 13:10 UTC (permalink / raw)
To: linux-media; +Cc: Mauricio Faria de Oliveira, Sakari Ailus, Hans Verkuil
In v4l2_device_unregister_subdev(), if sd->asc_list is empty,
then v4l2_device_unregister_subdev() is never called, but that
should still happen.
This causes crashes with em28xx that uses tvp5150: that i2c
module uses v4l2_async, but em28xx does not as it predates
v4l2_async.
So if sd->asc_list is empty, then just call
v4l2_device_unregister_subdev().
Fixes: 28a1295795d8 ("media: v4l: async: Allow multiple connections between entities")
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
---
drivers/media/v4l2-core/v4l2-async.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 888a2e213b08..fd0404ce9247 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -897,7 +897,9 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
kfree(sd->subdev_notifier);
sd->subdev_notifier = NULL;
- if (sd->asc_list.next) {
+ if (list_empty(&sd->asc_list)) {
+ v4l2_device_unregister_subdev(sd);
+ } else {
list_for_each_entry_safe(asc, asc_tmp, &sd->asc_list,
asc_subdev_entry) {
v4l2_async_unbind_subdev_one(asc->notifier, asc);
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCHv2 2/6] media: em28xx: use v4l2_device release callback
2026-06-16 13:10 [PATCHv2 0/6] media: em28xx: fix lifecycle issues Hans Verkuil
2026-06-16 13:10 ` [PATCHv2 1/6] media: core: v4l2-async.c: unreg subdev if asc_list is empty Hans Verkuil
@ 2026-06-16 13:10 ` Hans Verkuil
2026-06-16 13:10 ` [PATCHv2 3/6] media: em28xx: drop 'users' field Hans Verkuil
` (3 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Hans Verkuil @ 2026-06-16 13:10 UTC (permalink / raw)
To: linux-media; +Cc: Mauricio Faria de Oliveira, Sakari Ailus, Hans Verkuil
The em28xx driver creates a lot of video devices, but life-time management
is really bad. Instead use the struct v4l2_device release() callback to
have a single place where memory can be freed once the last user has gone.
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
---
drivers/media/usb/em28xx/em28xx-video.c | 66 +++++++++++++++----------
drivers/media/usb/em28xx/em28xx.h | 1 -
2 files changed, 41 insertions(+), 26 deletions(-)
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index da0422c65e5f..42f5e7547cc4 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -2275,18 +2275,27 @@ static int radio_s_tuner(struct file *file, void *priv,
}
/*
- * em28xx_free_v4l2() - Free struct em28xx_v4l2
+ * em28xx_free_v4l2() - v4l2_device release callback
*
- * @ref: struct kref for struct em28xx_v4l2
+ * @v4l2_dev: pointer to struct v4l2_device embedded in struct em28xx_v4l2
*
- * Called when all users of struct em28xx_v4l2 are gone
+ * Called by the v4l2 core when the last reference to the v4l2_device is
+ * released. At this point no userspace file handle nor video_device node
+ * keeps the v4l2 instance alive anymore, so it is safe to release all
+ * v4l2-related resources and drop the em28xx device reference taken when
+ * the v4l2 extension was initialized.
*/
-static void em28xx_free_v4l2(struct kref *ref)
+static void em28xx_free_v4l2(struct v4l2_device *v4l2_dev)
{
- struct em28xx_v4l2 *v4l2 = container_of(ref, struct em28xx_v4l2, ref);
+ struct em28xx_v4l2 *v4l2 =
+ container_of(v4l2_dev, struct em28xx_v4l2, v4l2_dev);
+ struct em28xx *dev = v4l2->dev;
- v4l2->dev->v4l2 = NULL;
+ v4l2_ctrl_handler_free(&v4l2->ctrl_handler);
+ v4l2_device_unregister(v4l2_dev);
+ dev->v4l2 = NULL;
kfree(v4l2);
+ kref_put(&dev->ref, em28xx_free_device);
}
/*
@@ -2354,8 +2363,6 @@ static int em28xx_v4l2_open(struct file *filp)
v4l2_device_call_all(&v4l2->v4l2_dev, 0, tuner, s_radio);
}
- kref_get(&dev->ref);
- kref_get(&v4l2->ref);
v4l2->users++;
mutex_unlock(&dev->lock);
@@ -2411,14 +2418,14 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
video_unregister_device(&v4l2->vdev);
}
- v4l2_ctrl_handler_free(&v4l2->ctrl_handler);
- v4l2_device_unregister(&v4l2->v4l2_dev);
-
- kref_put(&v4l2->ref, em28xx_free_v4l2);
-
mutex_unlock(&dev->lock);
- kref_put(&dev->ref, em28xx_free_device);
+ /*
+ * Drop the initial reference taken at v4l2_device_register() time.
+ * The em28xx_free_v4l2() release callback will be invoked once all
+ * userspace file handles to the video device nodes are closed.
+ */
+ v4l2_device_put(&v4l2->v4l2_dev);
return 0;
}
@@ -2490,9 +2497,7 @@ static int em28xx_v4l2_close(struct file *filp)
exit:
v4l2->users--;
- kref_put(&v4l2->ref, em28xx_free_v4l2);
mutex_unlock(&dev->lock);
- kref_put(&dev->ref, em28xx_free_device);
return 0;
}
@@ -2711,7 +2716,6 @@ static int em28xx_v4l2_init(struct em28xx *dev)
mutex_unlock(&dev->lock);
return -ENOMEM;
}
- kref_init(&v4l2->ref);
v4l2->dev = dev;
dev->v4l2 = v4l2;
@@ -2722,9 +2726,21 @@ static int em28xx_v4l2_init(struct em28xx *dev)
if (ret < 0) {
dev_err(&dev->intf->dev,
"Call to v4l2_device_register() failed!\n");
- goto err;
+ dev->v4l2 = NULL;
+ kfree(v4l2);
+ mutex_unlock(&dev->lock);
+ return ret;
}
+ /*
+ * From this point on, em28xx_free_v4l2() will be used to release
+ * v4l2-related resources when the v4l2_device refcount reaches
+ * zero. Take a reference to the em28xx device so that it cannot
+ * be freed before the v4l2 instance is released.
+ */
+ v4l2->v4l2_dev.release = em28xx_free_v4l2;
+ kref_get(&dev->ref);
+
hdl = &v4l2->ctrl_handler;
v4l2_ctrl_handler_init(hdl, 9);
v4l2->v4l2_dev.ctrl_handler = hdl;
@@ -3048,8 +3064,6 @@ static int em28xx_v4l2_init(struct em28xx *dev)
dev_info(&dev->intf->dev,
"V4L2 extension successfully initialized\n");
- kref_get(&dev->ref);
-
mutex_unlock(&dev->lock);
return 0;
@@ -3073,12 +3087,14 @@ static int em28xx_v4l2_init(struct em28xx *dev)
video_unregister_device(&v4l2->vdev);
}
- v4l2_ctrl_handler_free(&v4l2->ctrl_handler);
- v4l2_device_unregister(&v4l2->v4l2_dev);
-err:
- dev->v4l2 = NULL;
- kref_put(&v4l2->ref, em28xx_free_v4l2);
mutex_unlock(&dev->lock);
+
+ /*
+ * Drop the initial reference. em28xx_free_v4l2() will be called
+ * once the last video_device node release has decremented the
+ * v4l2_device refcount to zero.
+ */
+ v4l2_device_put(&v4l2->v4l2_dev);
return ret;
}
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 21c912403efc..90b83e4598ac 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -557,7 +557,6 @@ struct em28xx_eeprom {
#define EM28XX_RESOURCE_VBI 0x02
struct em28xx_v4l2 {
- struct kref ref;
struct em28xx *dev;
struct v4l2_device v4l2_dev;
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCHv2 3/6] media: em28xx: drop 'users' field
2026-06-16 13:10 [PATCHv2 0/6] media: em28xx: fix lifecycle issues Hans Verkuil
2026-06-16 13:10 ` [PATCHv2 1/6] media: core: v4l2-async.c: unreg subdev if asc_list is empty Hans Verkuil
2026-06-16 13:10 ` [PATCHv2 2/6] media: em28xx: use v4l2_device release callback Hans Verkuil
@ 2026-06-16 13:10 ` Hans Verkuil
2026-06-16 13:10 ` [PATCHv2 4/6] media: em28xx: use vb2_video_unregister_device Hans Verkuil
` (2 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Hans Verkuil @ 2026-06-16 13:10 UTC (permalink / raw)
To: linux-media; +Cc: Mauricio Faria de Oliveira, Sakari Ailus, Hans Verkuil
Drop the em28xx_v4l2 'users' field, use v4l2_fh_is_singular_file()
instead.
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
---
drivers/media/usb/em28xx/em28xx-video.c | 18 +++++++-----------
drivers/media/usb/em28xx/em28xx.h | 1 -
2 files changed, 7 insertions(+), 12 deletions(-)
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 42f5e7547cc4..6c726764a5f3 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -2332,9 +2332,8 @@ static int em28xx_v4l2_open(struct file *filp)
return -ENODEV;
}
- em28xx_videodbg("open dev=%s type=%s users=%d\n",
- video_device_node_name(vdev), v4l2_type_names[fh_type],
- v4l2->users);
+ em28xx_videodbg("open dev=%s type=%s\n",
+ video_device_node_name(vdev), v4l2_type_names[fh_type]);
ret = v4l2_fh_open(filp);
if (ret) {
@@ -2345,7 +2344,7 @@ static int em28xx_v4l2_open(struct file *filp)
return ret;
}
- if (v4l2->users == 0) {
+ if (v4l2_fh_is_singular_file(filp)) {
em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
if (vdev->vfl_type != VFL_TYPE_RADIO)
@@ -2363,8 +2362,6 @@ static int em28xx_v4l2_open(struct file *filp)
v4l2_device_call_all(&v4l2->v4l2_dev, 0, tuner, s_radio);
}
- v4l2->users++;
-
mutex_unlock(&dev->lock);
return 0;
@@ -2467,13 +2464,13 @@ static int em28xx_v4l2_close(struct file *filp)
struct em28xx_v4l2 *v4l2 = dev->v4l2;
struct usb_device *udev = interface_to_usbdev(dev->intf);
int err;
+ bool last_user;
- em28xx_videodbg("users=%d\n", v4l2->users);
-
- vb2_fop_release(filp);
mutex_lock(&dev->lock);
+ last_user = v4l2_fh_is_singular_file(filp);
+ _vb2_fop_release(filp, NULL);
- if (v4l2->users == 1) {
+ if (last_user) {
/* No sense to try to write to the device */
if (dev->disconnected)
goto exit;
@@ -2496,7 +2493,6 @@ static int em28xx_v4l2_close(struct file *filp)
}
exit:
- v4l2->users--;
mutex_unlock(&dev->lock);
return 0;
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 90b83e4598ac..f68159fab345 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -580,7 +580,6 @@ struct em28xx_v4l2 {
int sensor_yres;
int sensor_xtal;
- int users; /* user count for exclusive use */
int streaming_users; /* number of actively streaming users */
u32 frequency; /* selected tuner frequency */
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCHv2 4/6] media: em28xx: use vb2_video_unregister_device
2026-06-16 13:10 [PATCHv2 0/6] media: em28xx: fix lifecycle issues Hans Verkuil
` (2 preceding siblings ...)
2026-06-16 13:10 ` [PATCHv2 3/6] media: em28xx: drop 'users' field Hans Verkuil
@ 2026-06-16 13:10 ` Hans Verkuil
2026-06-16 13:10 ` [PATCHv2 5/6] media: em28xx: dev_info->pr_info since dev has been freed Hans Verkuil
2026-06-16 13:10 ` [PATCHv2 6/6] media: em28xx: requeue buffers if start_streaming fails Hans Verkuil
5 siblings, 0 replies; 8+ messages in thread
From: Hans Verkuil @ 2026-06-16 13:10 UTC (permalink / raw)
To: linux-media; +Cc: Mauricio Faria de Oliveira, Sakari Ailus, Hans Verkuil
Use vb2_video_unregister_device instead of video_unregister_device
to ensure any streaming is correctly stopped at unregister time.
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
---
drivers/media/usb/em28xx/em28xx-video.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 6c726764a5f3..e4554d015944 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -2402,17 +2402,17 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
if (video_is_registered(&v4l2->radio_dev)) {
dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n",
video_device_node_name(&v4l2->radio_dev));
- video_unregister_device(&v4l2->radio_dev);
+ vb2_video_unregister_device(&v4l2->radio_dev);
}
if (video_is_registered(&v4l2->vbi_dev)) {
dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n",
video_device_node_name(&v4l2->vbi_dev));
- video_unregister_device(&v4l2->vbi_dev);
+ vb2_video_unregister_device(&v4l2->vbi_dev);
}
if (video_is_registered(&v4l2->vdev)) {
dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n",
video_device_node_name(&v4l2->vdev));
- video_unregister_device(&v4l2->vdev);
+ vb2_video_unregister_device(&v4l2->vdev);
}
mutex_unlock(&dev->lock);
@@ -3068,19 +3068,19 @@ static int em28xx_v4l2_init(struct em28xx *dev)
dev_info(&dev->intf->dev,
"V4L2 device %s deregistered\n",
video_device_node_name(&v4l2->radio_dev));
- video_unregister_device(&v4l2->radio_dev);
+ vb2_video_unregister_device(&v4l2->radio_dev);
}
if (video_is_registered(&v4l2->vbi_dev)) {
dev_info(&dev->intf->dev,
"V4L2 device %s deregistered\n",
video_device_node_name(&v4l2->vbi_dev));
- video_unregister_device(&v4l2->vbi_dev);
+ vb2_video_unregister_device(&v4l2->vbi_dev);
}
if (video_is_registered(&v4l2->vdev)) {
dev_info(&dev->intf->dev,
"V4L2 device %s deregistered\n",
video_device_node_name(&v4l2->vdev));
- video_unregister_device(&v4l2->vdev);
+ vb2_video_unregister_device(&v4l2->vdev);
}
mutex_unlock(&dev->lock);
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCHv2 5/6] media: em28xx: dev_info->pr_info since dev has been freed
2026-06-16 13:10 [PATCHv2 0/6] media: em28xx: fix lifecycle issues Hans Verkuil
` (3 preceding siblings ...)
2026-06-16 13:10 ` [PATCHv2 4/6] media: em28xx: use vb2_video_unregister_device Hans Verkuil
@ 2026-06-16 13:10 ` Hans Verkuil
2026-06-16 13:10 ` [PATCHv2 6/6] media: em28xx: requeue buffers if start_streaming fails Hans Verkuil
5 siblings, 0 replies; 8+ messages in thread
From: Hans Verkuil @ 2026-06-16 13:10 UTC (permalink / raw)
To: linux-media; +Cc: Mauricio Faria de Oliveira, Sakari Ailus, Hans Verkuil
In em28xx_free_device() dev_info passed &dev->intf->dev,
but that device can be freed already.
Just use pr_info instead.
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
---
drivers/media/usb/em28xx/em28xx-cards.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index fbfb74eab475..4d1e48c86ce8 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -3758,7 +3758,7 @@ void em28xx_free_device(struct kref *ref)
{
struct em28xx *dev = kref_to_dev(ref);
- dev_info(&dev->intf->dev, "Freeing device\n");
+ pr_info("%s: Freeing device\n", dev->name);
if (!dev->disconnected)
em28xx_release_resources(dev);
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCHv2 6/6] media: em28xx: requeue buffers if start_streaming fails
2026-06-16 13:10 [PATCHv2 0/6] media: em28xx: fix lifecycle issues Hans Verkuil
` (4 preceding siblings ...)
2026-06-16 13:10 ` [PATCHv2 5/6] media: em28xx: dev_info->pr_info since dev has been freed Hans Verkuil
@ 2026-06-16 13:10 ` Hans Verkuil
5 siblings, 0 replies; 8+ messages in thread
From: Hans Verkuil @ 2026-06-16 13:10 UTC (permalink / raw)
To: linux-media; +Cc: Mauricio Faria de Oliveira, Sakari Ailus, Hans Verkuil
If start_streaming fails, then all queued buffers must be
returned to vb2 in state QUEUED.
Otherwise it will trigger a WARN_ON.
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
---
drivers/media/usb/em28xx/em28xx-video.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index e4554d015944..c418add65bb5 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -1213,6 +1213,9 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count)
{
struct em28xx *dev = vb2_get_drv_priv(vq);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
+ struct em28xx_dmaqueue *dmaq = vq->type == V4L2_BUF_TYPE_VBI_CAPTURE ?
+ &dev->vbiq : &dev->vidq;
+ unsigned long flags = 0;
struct v4l2_frequency f;
struct v4l2_fh *owner;
int rc = 0;
@@ -1227,7 +1230,7 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count)
*/
rc = res_get(dev, vq->type);
if (rc)
- return rc;
+ goto exit;
if (v4l2->streaming_users == 0) {
/* First active streaming user, so allocate all the URBs */
@@ -1250,7 +1253,7 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count)
em28xx_urb_data_copy);
if (rc < 0) {
res_free(dev, vq->type);
- return rc;
+ goto exit;
}
/*
@@ -1275,7 +1278,18 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count)
}
v4l2->streaming_users++;
+ return 0;
+exit:
+ spin_lock_irqsave(&dev->slock, flags);
+ while (!list_empty(&dmaq->active)) {
+ struct em28xx_buffer *buf;
+
+ buf = list_entry(dmaq->active.next, struct em28xx_buffer, list);
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED);
+ }
+ spin_unlock_irqrestore(&dev->slock, flags);
return rc;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCHv2 1/6] media: core: v4l2-async.c: unreg subdev if asc_list is empty
2026-06-16 13:10 ` [PATCHv2 1/6] media: core: v4l2-async.c: unreg subdev if asc_list is empty Hans Verkuil
@ 2026-06-16 15:15 ` Sakari Ailus
0 siblings, 0 replies; 8+ messages in thread
From: Sakari Ailus @ 2026-06-16 15:15 UTC (permalink / raw)
To: Hans Verkuil; +Cc: linux-media, Mauricio Faria de Oliveira
Hi Hans,
On Tue, Jun 16, 2026 at 03:10:27PM +0200, Hans Verkuil wrote:
> In v4l2_device_unregister_subdev(), if sd->asc_list is empty,
> then v4l2_device_unregister_subdev() is never called, but that
> should still happen.
>
> This causes crashes with em28xx that uses tvp5150: that i2c
> module uses v4l2_async, but em28xx does not as it predates
> v4l2_async.
>
> So if sd->asc_list is empty, then just call
> v4l2_device_unregister_subdev().
>
> Fixes: 28a1295795d8 ("media: v4l: async: Allow multiple connections between entities")
> Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
> ---
> drivers/media/v4l2-core/v4l2-async.c | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 888a2e213b08..fd0404ce9247 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -897,7 +897,9 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
> kfree(sd->subdev_notifier);
> sd->subdev_notifier = NULL;
>
> - if (sd->asc_list.next) {
> + if (list_empty(&sd->asc_list)) {
If v4l2_async_unregister_subdev() without calling
v4l2_async_register_subdev() first, sd->asc_list.next will be NULL. That
case needs to be handled here, too.
> + v4l2_device_unregister_subdev(sd);
> + } else {
> list_for_each_entry_safe(asc, asc_tmp, &sd->asc_list,
> asc_subdev_entry) {
> v4l2_async_unbind_subdev_one(asc->notifier, asc);
--
Kind regards,
Sakari Ailus
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-06-16 15:15 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-16 13:10 [PATCHv2 0/6] media: em28xx: fix lifecycle issues Hans Verkuil
2026-06-16 13:10 ` [PATCHv2 1/6] media: core: v4l2-async.c: unreg subdev if asc_list is empty Hans Verkuil
2026-06-16 15:15 ` Sakari Ailus
2026-06-16 13:10 ` [PATCHv2 2/6] media: em28xx: use v4l2_device release callback Hans Verkuil
2026-06-16 13:10 ` [PATCHv2 3/6] media: em28xx: drop 'users' field Hans Verkuil
2026-06-16 13:10 ` [PATCHv2 4/6] media: em28xx: use vb2_video_unregister_device Hans Verkuil
2026-06-16 13:10 ` [PATCHv2 5/6] media: em28xx: dev_info->pr_info since dev has been freed Hans Verkuil
2026-06-16 13:10 ` [PATCHv2 6/6] media: em28xx: requeue buffers if start_streaming fails Hans Verkuil
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox