From: Nicola Fiorillo <nicfio@gmail.com>
To: linux-media@vger.kernel.org
Cc: sakari.ailus@linux.intel.com, mchehab@kernel.org,
hverkuil@kernel.org, antti.laakso@linux.intel.com,
linux-kernel@vger.kernel.org, Nicola Fiorillo <nicfio@gmail.com>
Subject: [PATCH v2 3/3] media: ipu6: Signal the video queues when a sensor is unbound
Date: Fri, 11 Sep 2026 21:48:54 +0200 [thread overview]
Message-ID: <20260911194854.78894-4-nicfio@gmail.com> (raw)
In-Reply-To: <20260911194854.78894-1-nicfio@gmail.com>
isys_async_ops implements .bound() and .complete() but not .unbind(), so
nothing tells the ISYS video nodes that the sensor feeding them has gone
away. A capture that is streaming when the sensor is unbound stays
blocked in vb2_core_dqbuf() forever, waiting for a frame that can no
longer arrive:
[<0>] vb2_core_dqbuf+0x362/0x1190 [videobuf2_common]
[<0>] vb2_dqbuf+0xb4/0x210 [videobuf2_v4l2]
[<0>] __video_do_ioctl+0x894/0xb30
[<0>] video_usercopy+0x479/0xde0
[<0>] v4l2_ioctl+0x198/0x220
[<0>] __x64_sys_ioctl+0x134/0x1c0
The wait in __vb2_wait_for_done_vb() ends on a new buffer, on
!q->streaming, or on q->error. Tearing the sensor down sets none of the
three. The sleep is interruptible, so DETECT_HUNG_TASK stays quiet as
well and the process is simply stuck until something kills it.
Add the missing .unbind() and mark the queues of the CSI-2 receiver the
departing sensor was attached to, which is enough for DQBUF to return
-EIO. Only streaming queues are flagged: q->error is cleared by
__vb2_queue_cancel(), so flagging an idle queue would leave it in error
until the next VIDIOC_STREAMOFF.
Reproduced on a CHUWI Hi10 X1 (Alder Lake-N, IPU6) by unbinding the
sensor while v4l2-ctl was streaming, with both sensors of the machine.
Without this patch 3 attempts out of 3 hang; with it, 10 out of 10 wake
up, report "VIDIOC_DQBUF: failed: Input/output error" and exit. The same
run under KASAN reports nothing.
Fixes: f50c4ca0a820 ("media: intel/ipu6: add the main input system driver")
Signed-off-by: Nicola Fiorillo <nicfio@gmail.com>
---
Unchanged since v1; the note below is new.
The check and the marking are deliberately not done under q->lock, and I
would rather say so than have it look like an oversight.
The lock of these queues is av->mutex (aq->vbq.lock, ipu6-isys-queue.c),
and taking it here is not possible as the teardown stands: isys_remove()
calls isys_unregister_devices() before isys_notifier_cleanup(), and the
former ends in ipu6_isys_video_cleanup() -> mutex_destroy(&av->mutex).
So on driver removal this callback runs after that mutex has been
destroyed, and taking it would be an OOPS with CONFIG_DEBUG_MUTEXES.
Without the lock there is a narrow race with a concurrent STREAMOFF (an
idle queue left flagged until the next STREAMOFF) or STREAMON (the hang
comes back). The unlocked read is safe in the removal path itself,
because vb2_video_unregister_device() has already released the queue
under the lock, so vb2_is_streaming() is false there and the loop does
nothing.
The proper fix looks like unregistering the notifier before the video
devices, which would also make teardown the mirror of setup --
isys_register_devices() registers the video devices first and inits the
notifier last, and its own error path unwinds in that order. I did not
put that in this series because I cannot build or test a kernel at the
moment, and changing the removal path untested seemed worse than leaving
this documented. I am happy to write it as a follow-up if you agree with
the direction.
drivers/media/pci/intel/ipu6/ipu6-isys.c | 41 ++++++++++++++++++++++++
1 file changed, 41 insertions(+)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index c9cdeb705..8055ae169 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -31,6 +31,7 @@
#include <media/v4l2-async.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fwnode.h>
+#include <media/videobuf2-core.h>
#include "ipu6-bus.h"
#include "ipu6-cpd.h"
@@ -700,6 +701,45 @@ static int isys_notifier_bound(struct v4l2_async_notifier *notifier,
return v4l2_device_register_subdev_nodes(&isys->v4l2_dev);
}
+/* The .unbind() notifier callback when a sub-device goes away */
+static void isys_notifier_unbind(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *sd,
+ struct v4l2_async_connection *asc)
+{
+ struct ipu6_isys *isys =
+ container_of(notifier, struct ipu6_isys, notifier);
+ struct sensor_async_sd *s_asd =
+ container_of(asc, struct sensor_async_sd, asc);
+ struct ipu6_isys_csi2 *csi2;
+ unsigned int i;
+
+ if (s_asd->csi2.port >= isys->pdata->ipdata->csi2.nports)
+ return;
+
+ /*
+ * The sensor is gone, so no more frames will ever arrive on the video
+ * nodes fed by it. Tell videobuf2, or a DQBUF already blocked in
+ * vb2_core_dqbuf() would sleep forever: nothing else in the teardown
+ * path wakes that queue up.
+ *
+ * Only queues that are actually streaming are marked. The error flag
+ * is only cleared by __vb2_queue_cancel(), so flagging an idle queue
+ * would leave it poisoned until the next STREAMOFF.
+ */
+ csi2 = &isys->csi2[s_asd->csi2.port];
+ for (i = 0; i < NR_OF_CSI2_SRC_PADS; i++) {
+ struct vb2_queue *q = &csi2->av[i].aq.vbq;
+
+ if (!vb2_is_streaming(q))
+ continue;
+
+ dev_dbg(&isys->adev->auxdev.dev,
+ "%s went away while streaming on %s\n", sd->name,
+ csi2->av[i].vdev.name);
+ vb2_queue_error(q);
+ }
+}
+
static int isys_notifier_complete(struct v4l2_async_notifier *notifier)
{
struct ipu6_isys *isys =
@@ -710,6 +750,7 @@ static int isys_notifier_complete(struct v4l2_async_notifier *notifier)
static const struct v4l2_async_notifier_operations isys_async_ops = {
.bound = isys_notifier_bound,
+ .unbind = isys_notifier_unbind,
.complete = isys_notifier_complete,
};
--
2.47.3
next prev parent reply other threads:[~2026-09-11 19:49 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-11 19:48 [PATCH v2 0/3] media: Two oopses and a hang when unbinding a streaming sensor Nicola Fiorillo
2026-09-11 19:48 ` [PATCH v2 1/3] media: ipu6: Check the remote pad before dereferencing it Nicola Fiorillo
2026-09-11 19:48 ` [PATCH v2 2/3] media: v4l2-subdev: Check v4l2_dev before dereferencing it in open() Nicola Fiorillo
2026-09-11 19:48 ` Nicola Fiorillo [this message]
2026-09-12 10:23 ` [PATCH v2 0/3] media: Two oopses and a hang when unbinding a streaming sensor Sakari Ailus
2026-09-12 11:20 ` Nicola Fiorillo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260911194854.78894-4-nicfio@gmail.com \
--to=nicfio@gmail.com \
--cc=antti.laakso@linux.intel.com \
--cc=hverkuil@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=mchehab@kernel.org \
--cc=sakari.ailus@linux.intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.