summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSakari Ailus <sakari.ailus@linux.intel.com>2025-11-21 14:48:40 +0300
committerHans Verkuil <hverkuil+cisco@kernel.org>2026-01-15 01:33:02 +0300
commit7345d6d356336c448d6b9230ed8704f39679fd12 (patch)
treea499b427d043c570de43c21440db75ec848588d9
parent679f0b7b6a409750a25754c8833e268e5fdde742 (diff)
downloadlinux-7345d6d356336c448d6b9230ed8704f39679fd12.tar.xz
media: v4l2-async: Fix error handling on steps after finding a match
Once an async connection is found to be matching with an fwnode, a sub-device may be registered (in case it wasn't already), its bound operation is called, ancillary links are created, the async connection is added to the sub-device's list of connections and removed from the global waiting connection list. Further on, the sub-device's possible own notifier is searched for possible additional matches. Fix these specific issues: - If v4l2_async_match_notify() failed before the sub-notifier handling, the async connection was unbound and its entry removed from the sub-device's async connection list. The latter part was also done in v4l2_async_match_notify(). - The async connection's sd field was only set after creating ancillary links in v4l2_async_match_notify(). It was however dereferenced in v4l2_async_unbind_subdev_one(), which was called on error path of v4l2_async_match_notify() failure. Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> Tested-by: "Yew, Chang Ching" <chang.ching.yew@intel.com> Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
-rw-r--r--drivers/media/v4l2-core/v4l2-async.c45
1 files changed, 31 insertions, 14 deletions
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index ee884a8221fb..1c08bba9ecb9 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -343,7 +343,6 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
struct v4l2_subdev *sd,
struct v4l2_async_connection *asc)
{
- struct v4l2_async_notifier *subdev_notifier;
bool registered = false;
int ret;
@@ -389,6 +388,25 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
dev_dbg(notifier_dev(notifier), "v4l2-async: %s bound (ret %d)\n",
dev_name(sd->dev), ret);
+ return 0;
+
+err_call_unbind:
+ v4l2_async_nf_call_unbind(notifier, sd, asc);
+ list_del(&asc->asc_subdev_entry);
+
+err_unregister_subdev:
+ if (registered)
+ v4l2_device_unregister_subdev(sd);
+
+ return ret;
+}
+
+static int
+v4l2_async_nf_try_subdev_notifier(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *sd)
+{
+ struct v4l2_async_notifier *subdev_notifier;
+
/*
* See if the sub-device has a notifier. If not, return here.
*/
@@ -404,16 +422,6 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
subdev_notifier->parent = notifier;
return v4l2_async_nf_try_all_subdevs(subdev_notifier);
-
-err_call_unbind:
- v4l2_async_nf_call_unbind(notifier, sd, asc);
- list_del(&asc->asc_subdev_entry);
-
-err_unregister_subdev:
- if (registered)
- v4l2_device_unregister_subdev(sd);
-
- return ret;
}
/* Test all async sub-devices in a notifier for a match. */
@@ -445,6 +453,10 @@ again:
if (ret < 0)
return ret;
+ ret = v4l2_async_nf_try_subdev_notifier(notifier, sd);
+ if (ret < 0)
+ return ret;
+
/*
* v4l2_async_match_notify() may lead to registering a
* new notifier and thus changing the async subdevs
@@ -829,7 +841,11 @@ int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module)
ret = v4l2_async_match_notify(notifier, v4l2_dev, sd,
asc);
if (ret)
- goto err_unbind;
+ goto err_unlock;
+
+ ret = v4l2_async_nf_try_subdev_notifier(notifier, sd);
+ if (ret)
+ goto err_unbind_one;
ret = v4l2_async_nf_try_complete(notifier);
if (ret)
@@ -853,9 +869,10 @@ err_unbind:
if (subdev_notifier)
v4l2_async_nf_unbind_all_subdevs(subdev_notifier);
- if (asc)
- v4l2_async_unbind_subdev_one(notifier, asc);
+err_unbind_one:
+ v4l2_async_unbind_subdev_one(notifier, asc);
+err_unlock:
mutex_unlock(&list_lock);
sd->owner = NULL;