From patchwork Sat Mar 26 04:38:44 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shuah Khan X-Patchwork-Id: 8674011 Return-Path: X-Original-To: patchwork-linux-media@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id AC2A3C0553 for ; Sat, 26 Mar 2016 04:39:52 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 9B4D220279 for ; Sat, 26 Mar 2016 04:39:51 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 2BFED202E5 for ; Sat, 26 Mar 2016 04:39:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751780AbcCZEiv (ORCPT ); Sat, 26 Mar 2016 00:38:51 -0400 Received: from mailout.easymail.ca ([64.68.201.169]:49995 "EHLO mailout.easymail.ca" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750848AbcCZEiu (ORCPT ); Sat, 26 Mar 2016 00:38:50 -0400 Received: from localhost (localhost [127.0.0.1]) by mailout.easymail.ca (Postfix) with ESMTP id 4F826F45C; Sat, 26 Mar 2016 00:38:48 -0400 (EDT) X-Quarantine-ID: X-Virus-Scanned: Debian amavisd-new at mailout.easymail.ca X-Amavis-Alert: BAD HEADER SECTION, Duplicate header field: "References" X-Spam-Score: -3.694 X-Spam-Level: X-Spam-Status: No, score=-7.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from mailout.easymail.ca ([127.0.0.1]) by localhost (easymail-mailout.easydns.vpn [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id YYbe8VvpMdbI; Sat, 26 Mar 2016 00:38:48 -0400 (EDT) Received: from mail.gonehiking.org (c-73-181-52-62.hsd1.co.comcast.net [73.181.52.62]) by mailout.easymail.ca (Postfix) with ESMTPA id E6D45F2F2; Sat, 26 Mar 2016 00:38:47 -0400 (EDT) Received: from lorien.internal (lorien-wl.internal [192.168.1.40]) by mail.gonehiking.org (Postfix) with ESMTP id 8E1719F2FE; Fri, 25 Mar 2016 22:38:47 -0600 (MDT) From: Shuah Khan To: laurent.pinchart@ideasonboard.com, mchehab@osg.samsung.com, perex@perex.cz, tiwai@suse.com, hans.verkuil@cisco.com, chehabrafael@gmail.com, javier@osg.samsung.com, jh1009.sung@samsung.com Cc: Shuah Khan , linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, alsa-devel@alsa-project.org Subject: [RFC PATCH 3/4] media: Add refcount to keep track of media device registrations Date: Fri, 25 Mar 2016 22:38:44 -0600 Message-Id: X-Mailer: git-send-email 2.5.0 In-Reply-To: References: In-Reply-To: References: Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add refcount to keep track of media device registrations to avoid release of media device when one of the drivers does unregister when media device belongs to more than one driver. Also add a new interfaces to unregister a media device allocated using Media Device Allocator and a hold register refcount. Change media_open() to get media device reference and put the reference in media_release(). Signed-off-by: Shuah Khan --- drivers/media/media-device.c | 53 +++++++++++++++++++++++++++++++++++++++++++ drivers/media/media-devnode.c | 3 +++ include/media/media-device.h | 32 ++++++++++++++++++++++++++ 3 files changed, 88 insertions(+) diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index 93aff4e..3359235 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -36,6 +36,7 @@ #include #include #include +#include #ifdef CONFIG_MEDIA_CONTROLLER @@ -702,6 +703,7 @@ void media_device_init(struct media_device *mdev) INIT_LIST_HEAD(&mdev->entity_notify); mutex_init(&mdev->graph_mutex); ida_init(&mdev->entity_internal_idx); + kref_init(&mdev->refcount); dev_dbg(mdev->dev, "Media device initialized\n"); } @@ -730,6 +732,13 @@ printk("%s: mdev %p\n", __func__, mdev); /* Check if mdev was ever registered at all */ mutex_lock(&mdev->graph_mutex); + /* if media device is already registered, bump the register refcount */ + if (media_devnode_is_registered(&mdev->devnode)) { + kref_get(&mdev->refcount); + mutex_unlock(&mdev->graph_mutex); + return 0; + } + /* Register the device node. */ mdev->devnode.fops = &media_device_fops; mdev->devnode.parent = mdev->dev; @@ -756,6 +765,22 @@ err: } EXPORT_SYMBOL_GPL(__media_device_register); +void media_device_register_ref(struct media_device *mdev) +{ + if (!mdev) + return; + + pr_info("%s: mdev %p\n", __func__, mdev); + mutex_lock(&mdev->graph_mutex); + + /* Check if mdev is registered - bump registered refcount */ + if (media_devnode_is_registered(&mdev->devnode)) + kref_get(&mdev->refcount); + + mutex_unlock(&mdev->graph_mutex); +} +EXPORT_SYMBOL_GPL(media_device_register_ref); + int __must_check media_device_register_entity_notify(struct media_device *mdev, struct media_entity_notify *nptr) { @@ -829,6 +854,34 @@ printk("%s: mdev=%p\n", __func__, mdev); } EXPORT_SYMBOL_GPL(media_device_unregister); +static void __media_device_unregister_kref(struct kref *kref) +{ + struct media_device *mdev; + + mdev = container_of(kref, struct media_device, refcount); + __media_device_unregister(mdev); +} + +void media_device_unregister_put(struct media_device *mdev) +{ + int ret; + + if (mdev == NULL) + return; + + pr_info("%s: mdev=%p\n", __func__, mdev); + ret = kref_put_mutex(&mdev->refcount, __media_device_unregister_kref, + &mdev->graph_mutex); + if (ret) { + /* __media_device_unregister() ran */ + __media_device_cleanup(mdev); + mutex_unlock(&mdev->graph_mutex); + mutex_destroy(&mdev->graph_mutex); + media_device_set_to_delete_state(mdev->dev); + } +} +EXPORT_SYMBOL_GPL(media_device_unregister_put); + static void media_device_release_devres(struct device *dev, void *res) { } diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c index 29409f4..d1d1263 100644 --- a/drivers/media/media-devnode.c +++ b/drivers/media/media-devnode.c @@ -44,6 +44,7 @@ #include #include +#include #define MEDIA_NUM_DEVICES 256 #define MEDIA_NAME "media" @@ -186,6 +187,7 @@ static int media_open(struct inode *inode, struct file *filp) } } + media_device_get_ref(mdev->parent); return 0; } @@ -201,6 +203,7 @@ static int media_release(struct inode *inode, struct file *filp) return value is ignored. */ put_device(&mdev->dev); filp->private_data = NULL; + media_device_put(mdev->parent); return 0; } diff --git a/include/media/media-device.h b/include/media/media-device.h index e59772e..64114ae 100644 --- a/include/media/media-device.h +++ b/include/media/media-device.h @@ -284,6 +284,8 @@ struct media_entity_notify { * struct media_device - Media device * @dev: Parent device * @devnode: Media device node + * @refcount: Media device register reference count. Used when more + * than one driver owns the device. * @driver_name: Optional device driver name. If not set, calls to * %MEDIA_IOC_DEVICE_INFO will return dev->driver->name. * This is needed for USB drivers for example, as otherwise @@ -348,6 +350,7 @@ struct media_device { /* dev->driver_data points to this struct. */ struct device *dev; struct media_devnode devnode; + struct kref refcount; char model[32]; char driver_name[32]; @@ -501,6 +504,17 @@ int __must_check __media_device_register(struct media_device *mdev, #define media_device_register(mdev) __media_device_register(mdev, THIS_MODULE) /** + * media_device_register_ref() - Increments media device register refcount + * + * @mdev: pointer to struct &media_device + * + * When more than one driver is associated with the media device, it is + * necessary to refcount the number of registrations to avoid unregister + * when it is still in use. + */ +void media_device_register_ref(struct media_device *mdev); + +/** * media_device_unregister() - Unregisters a media device element * * @mdev: pointer to struct &media_device @@ -512,6 +526,18 @@ int __must_check __media_device_register(struct media_device *mdev, void media_device_unregister(struct media_device *mdev); /** + * media_device_unregister_put() - Unregisters a media device element + * + * @mdev: pointer to struct &media_device + * + * Should be called to unregister media device allocated with Media Device + * Allocator API media_device_get() interface. + * It is safe to call this function on an unregistered (but initialised) + * media device. + */ +void media_device_unregister_put(struct media_device *mdev); + +/** * media_device_register_entity() - registers a media entity inside a * previously registered media device. * @@ -681,9 +707,15 @@ static inline int media_device_register(struct media_device *mdev) { return 0; } +static inline void media_device_register_ref(struct media_device *mdev) +{ +} static inline void media_device_unregister(struct media_device *mdev) { } +static inline void media_device_unregister_put(struct media_device *mdev) +{ +} static inline int media_device_register_entity(struct media_device *mdev, struct media_entity *entity) {