mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
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


  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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®