| From f0d3311fc01ce963aed5c4e6ca4136b05bbd8860 Mon Sep 17 00:00:00 2001 |
| From: Sakari Ailus <sakari.ailus@linux.intel.com> |
| Date: Mon, 2 Oct 2017 06:24:54 -0400 |
| Subject: [PATCH 0288/1795] media: v4l: async: Fix notifier complete callback |
| error handling |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| The notifier complete callback may return an error. This error code was |
| simply returned to the caller but never handled properly. |
| |
| Move calling the complete callback function to the caller from |
| v4l2_async_test_notify and undo the work that was done either in async |
| sub-device or async notifier registration. |
| |
| Reported-by: Russell King <rmk+kernel@armlinux.org.uk> |
| Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> |
| Acked-by: Niklas Sรถderlund <niklas.soderlund+renesas@ragnatech.se> |
| Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> |
| Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com> |
| (cherry picked from commit fb45f436b8186cafc95939087ce1dc565be26c3d) |
| Signed-off-by: Simon Horman <horms+renesas@verge.net.au> |
| Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be> |
| --- |
| drivers/media/v4l2-core/v4l2-async.c | 78 +++++++++++++++++++++------- |
| 1 file changed, 60 insertions(+), 18 deletions(-) |
| |
| diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c |
| index 325ec4062b4f..e36d6274a692 100644 |
| --- a/drivers/media/v4l2-core/v4l2-async.c |
| +++ b/drivers/media/v4l2-core/v4l2-async.c |
| @@ -123,9 +123,6 @@ static int v4l2_async_test_notify(struct v4l2_async_notifier *notifier, |
| /* Move from the global subdevice list to notifier's done */ |
| list_move(&sd->async_list, ¬ifier->done); |
| |
| - if (list_empty(¬ifier->waiting) && notifier->complete) |
| - return notifier->complete(notifier); |
| - |
| return 0; |
| } |
| |
| @@ -137,11 +134,27 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd) |
| sd->asd = NULL; |
| } |
| |
| +static void v4l2_async_notifier_unbind_all_subdevs( |
| + struct v4l2_async_notifier *notifier) |
| +{ |
| + struct v4l2_subdev *sd, *tmp; |
| + |
| + list_for_each_entry_safe(sd, tmp, ¬ifier->done, async_list) { |
| + if (notifier->unbind) |
| + notifier->unbind(notifier, sd, sd->asd); |
| + |
| + v4l2_async_cleanup(sd); |
| + |
| + list_move(&sd->async_list, &subdev_list); |
| + } |
| +} |
| + |
| int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, |
| struct v4l2_async_notifier *notifier) |
| { |
| struct v4l2_subdev *sd, *tmp; |
| struct v4l2_async_subdev *asd; |
| + int ret; |
| int i; |
| |
| if (!v4l2_dev || !notifier->num_subdevs || |
| @@ -186,19 +199,30 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, |
| } |
| } |
| |
| + if (list_empty(¬ifier->waiting) && notifier->complete) { |
| + ret = notifier->complete(notifier); |
| + if (ret) |
| + goto err_complete; |
| + } |
| + |
| /* Keep also completed notifiers on the list */ |
| list_add(¬ifier->list, ¬ifier_list); |
| |
| mutex_unlock(&list_lock); |
| |
| return 0; |
| + |
| +err_complete: |
| + v4l2_async_notifier_unbind_all_subdevs(notifier); |
| + |
| + mutex_unlock(&list_lock); |
| + |
| + return ret; |
| } |
| EXPORT_SYMBOL(v4l2_async_notifier_register); |
| |
| void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) |
| { |
| - struct v4l2_subdev *sd, *tmp; |
| - |
| if (!notifier->v4l2_dev) |
| return; |
| |
| @@ -206,14 +230,7 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) |
| |
| list_del(¬ifier->list); |
| |
| - list_for_each_entry_safe(sd, tmp, ¬ifier->done, async_list) { |
| - if (notifier->unbind) |
| - notifier->unbind(notifier, sd, sd->asd); |
| - |
| - v4l2_async_cleanup(sd); |
| - |
| - list_move(&sd->async_list, &subdev_list); |
| - } |
| + v4l2_async_notifier_unbind_all_subdevs(notifier); |
| |
| mutex_unlock(&list_lock); |
| |
| @@ -254,6 +271,7 @@ EXPORT_SYMBOL_GPL(v4l2_async_notifier_cleanup); |
| int v4l2_async_register_subdev(struct v4l2_subdev *sd) |
| { |
| struct v4l2_async_notifier *notifier; |
| + int ret; |
| |
| /* |
| * No reference taken. The reference is held by the device |
| @@ -269,19 +287,43 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd) |
| |
| list_for_each_entry(notifier, ¬ifier_list, list) { |
| struct v4l2_async_subdev *asd = v4l2_async_belongs(notifier, sd); |
| - if (asd) { |
| - int ret = v4l2_async_test_notify(notifier, sd, asd); |
| - mutex_unlock(&list_lock); |
| - return ret; |
| - } |
| + int ret; |
| + |
| + if (!asd) |
| + continue; |
| + |
| + ret = v4l2_async_test_notify(notifier, sd, asd); |
| + if (ret) |
| + goto err_unlock; |
| + |
| + if (!list_empty(¬ifier->waiting) || !notifier->complete) |
| + goto out_unlock; |
| + |
| + ret = notifier->complete(notifier); |
| + if (ret) |
| + goto err_cleanup; |
| + |
| + goto out_unlock; |
| } |
| |
| /* None matched, wait for hot-plugging */ |
| list_add(&sd->async_list, &subdev_list); |
| |
| +out_unlock: |
| mutex_unlock(&list_lock); |
| |
| return 0; |
| + |
| +err_cleanup: |
| + if (notifier->unbind) |
| + notifier->unbind(notifier, sd, sd->asd); |
| + |
| + v4l2_async_cleanup(sd); |
| + |
| +err_unlock: |
| + mutex_unlock(&list_lock); |
| + |
| + return ret; |
| } |
| EXPORT_SYMBOL(v4l2_async_register_subdev); |
| |
| -- |
| 2.19.0 |
| |