]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
media: v4l2-async: Fix error handling on steps after finding a match
authorSakari Ailus <sakari.ailus@linux.intel.com>
Fri, 21 Nov 2025 11:48:40 +0000 (13:48 +0200)
committerHans Verkuil <hverkuil+cisco@kernel.org>
Wed, 14 Jan 2026 22:33:02 +0000 (23:33 +0100)
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>
drivers/media/v4l2-core/v4l2-async.c

index ee884a8221fbd3b0ad83dc619100f8eea88cdc15..1c08bba9ecb91f46b7479da613d6c1688d4b0b5c 100644 (file)
@@ -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;