From patchwork Tue Feb 14 13:39:56 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Machek X-Patchwork-Id: 9572015 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id E690D6045F for ; Tue, 14 Feb 2017 13:42:09 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D940F27F4B for ; Tue, 14 Feb 2017 13:42:09 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id CE17027FA8; Tue, 14 Feb 2017 13:42:09 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0373F27F4B for ; Tue, 14 Feb 2017 13:42:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754106AbdBNNmG (ORCPT ); Tue, 14 Feb 2017 08:42:06 -0500 Received: from atrey.karlin.mff.cuni.cz ([195.113.26.193]:59094 "EHLO atrey.karlin.mff.cuni.cz" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753968AbdBNNj6 (ORCPT ); Tue, 14 Feb 2017 08:39:58 -0500 Received: by atrey.karlin.mff.cuni.cz (Postfix, from userid 512) id C3592817E1; Tue, 14 Feb 2017 14:39:56 +0100 (CET) Date: Tue, 14 Feb 2017 14:39:56 +0100 From: Pavel Machek To: sakari.ailus@iki.fi Cc: sre@kernel.org, pali.rohar@gmail.com, pavel@ucw.cz, linux-media@vger.kernel.org, linux-kernel@vger.kernel.org, laurent.pinchart@ideasonboard.com, mchehab@kernel.org, ivo.g.dimitrov.75@gmail.com Subject: [RFC 06/13] v4l2-async: per notifier locking Message-ID: <20170214133956.GA8530@amd> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.23 (2014-03-12) Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Sebastian Reichel Without this, camera support breaks boot on N900. Signed-off-by: Ivaylo Dimitrov Signed-off-by: Sebastian Reichel --- drivers/media/v4l2-core/v4l2-async.c | 54 ++++++++++++++++++------------------ include/media/v4l2-async.h | 2 ++ 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index 96cc733..26492a2 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -57,7 +57,6 @@ static bool match_custom(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) static LIST_HEAD(subdev_list); static LIST_HEAD(notifier_list); -static DEFINE_MUTEX(list_lock); static struct v4l2_async_subdev *v4l2_async_belongs(struct v4l2_async_notifier *notifier, struct v4l2_subdev *sd) @@ -102,12 +101,15 @@ static int v4l2_async_test_notify(struct v4l2_async_notifier *notifier, if (notifier->bound) { ret = notifier->bound(notifier, sd, asd); - if (ret < 0) + if (ret < 0) { + dev_warn(notifier->v4l2_dev->dev, "subdev bound failed\n"); return ret; + } } ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd); if (ret < 0) { + dev_warn(notifier->v4l2_dev->dev, "subdev register failed\n"); if (notifier->unbind) notifier->unbind(notifier, sd, asd); return ret; @@ -141,7 +143,7 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, { struct v4l2_subdev *sd, *tmp; struct v4l2_async_subdev *asd; - int i; + int ret = 0, i; if (!notifier->num_subdevs || notifier->num_subdevs > V4L2_MAX_SUBDEVS) return -EINVAL; @@ -149,6 +151,7 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, notifier->v4l2_dev = v4l2_dev; INIT_LIST_HEAD(¬ifier->waiting); INIT_LIST_HEAD(¬ifier->done); + mutex_init(¬ifier->lock); for (i = 0; i < notifier->num_subdevs; i++) { asd = notifier->subdevs[i]; @@ -168,28 +171,22 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, list_add_tail(&asd->list, ¬ifier->waiting); } - mutex_lock(&list_lock); + /* Keep also completed notifiers on the list */ + list_add(¬ifier->list, ¬ifier_list); + mutex_lock(¬ifier->lock); list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) { - int ret; - asd = v4l2_async_belongs(notifier, sd); if (!asd) continue; ret = v4l2_async_test_notify(notifier, sd, asd); - if (ret < 0) { - mutex_unlock(&list_lock); - return ret; - } + if (ret < 0) + break; } + mutex_unlock(¬ifier->lock); - /* Keep also completed notifiers on the list */ - list_add(¬ifier->list, ¬ifier_list); - - mutex_unlock(&list_lock); - - return 0; + return ret; } EXPORT_SYMBOL(v4l2_async_notifier_register); @@ -210,7 +207,7 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) "Failed to allocate device cache!\n"); } - mutex_lock(&list_lock); + mutex_lock(¬ifier->lock); list_del(¬ifier->list); @@ -237,7 +234,7 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) put_device(d); } - mutex_unlock(&list_lock); + mutex_unlock(¬ifier->lock); /* * Call device_attach() to reprobe devices @@ -262,6 +259,7 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) } kfree(dev); + mutex_destroy(¬ifier->lock); notifier->v4l2_dev = NULL; /* @@ -274,6 +272,7 @@ EXPORT_SYMBOL(v4l2_async_notifier_unregister); int v4l2_async_register_subdev(struct v4l2_subdev *sd) { struct v4l2_async_notifier *notifier; + struct v4l2_async_notifier *tmp; /* * No reference taken. The reference is held by the device @@ -283,24 +282,25 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd) if (!sd->of_node && sd->dev) sd->of_node = sd->dev->of_node; - mutex_lock(&list_lock); - INIT_LIST_HEAD(&sd->async_list); - list_for_each_entry(notifier, ¬ifier_list, list) { - struct v4l2_async_subdev *asd = v4l2_async_belongs(notifier, sd); + list_for_each_entry_safe(notifier, tmp, ¬ifier_list, list) { + struct v4l2_async_subdev *asd; + + /* TODO: FIXME: if this is called by ->bound() we will also iterate over the locked notifier */ + mutex_lock_nested(¬ifier->lock, SINGLE_DEPTH_NESTING); + asd = v4l2_async_belongs(notifier, sd); if (asd) { int ret = v4l2_async_test_notify(notifier, sd, asd); - mutex_unlock(&list_lock); + mutex_unlock(¬ifier->lock); return ret; } + mutex_unlock(¬ifier->lock); } /* None matched, wait for hot-plugging */ list_add(&sd->async_list, &subdev_list); - mutex_unlock(&list_lock); - return 0; } EXPORT_SYMBOL(v4l2_async_register_subdev); @@ -315,7 +315,7 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd) return; } - mutex_lock(&list_lock); + mutex_lock_nested(¬ifier->lock, SINGLE_DEPTH_NESTING); list_add(&sd->asd->list, ¬ifier->waiting); @@ -324,6 +324,6 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd) if (notifier->unbind) notifier->unbind(notifier, sd, sd->asd); - mutex_unlock(&list_lock); + mutex_unlock(¬ifier->lock); } EXPORT_SYMBOL(v4l2_async_unregister_subdev); diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h index 8e2a236..690a81f 100644 --- a/include/media/v4l2-async.h +++ b/include/media/v4l2-async.h @@ -84,6 +84,7 @@ struct v4l2_async_subdev { * @waiting: list of struct v4l2_async_subdev, waiting for their drivers * @done: list of struct v4l2_subdev, already probed * @list: member in a global list of notifiers + * @lock: lock hold when the notifier is being processed * @bound: a subdevice driver has successfully probed one of subdevices * @complete: all subdevices have been probed successfully * @unbind: a subdevice is leaving @@ -95,6 +96,7 @@ struct v4l2_async_notifier { struct list_head waiting; struct list_head done; struct list_head list; + struct mutex lock; int (*bound)(struct v4l2_async_notifier *notifier, struct v4l2_subdev *subdev, struct v4l2_async_subdev *asd);