From patchwork Wed Dec 20 10:36:45 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sakari Ailus X-Patchwork-Id: 756747 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E1B2B208DF for ; Wed, 20 Dec 2023 10:37:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="n08vFq4d" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1703068641; x=1734604641; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=fn5vdqTgrAwxvRPY8aEkpwtLLDHNckvF5vsntZp7xeE=; b=n08vFq4dquIqyXkwV4tARzvC2JBNbMinLia5xRRa9+xjkyq1SxPbhtIA sJklQJCrQokicqv//C2b4Pn1RZAEt6YPNLtGbCUagi9/Q+QkIZo8X1w3O kyAKiQJ01Zno/WQxNi4AymHNvMs8ZUlpj0BUufh8lY2dzG+0a0pho+s06 OYaVQTQM3Mt9nOJrlZZS1SFMLJ2JdtIGKFVBFFn1osWBluSE/NLFhru23 00kYaBe4f8Y77cZJLlBqKyPP0FwXg0weYrRW5clgb1E/wTdSBFDRg78UH IR43X/YYY2JPX2H18/g1b+G4uINCl7ENyQmR8tKzFGxkOzasUVCijWSfN Q==; X-IronPort-AV: E=McAfee;i="6600,9927,10929"; a="9174301" X-IronPort-AV: E=Sophos;i="6.04,291,1695711600"; d="scan'208";a="9174301" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2023 02:37:19 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10929"; a="769544226" X-IronPort-AV: E=Sophos;i="6.04,291,1695711600"; d="scan'208";a="769544226" Received: from turnipsi.fi.intel.com (HELO kekkonen.fi.intel.com) ([10.237.72.44]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2023 02:37:17 -0800 Received: from svinhufvud.ger.corp.intel.com (localhost [IPv6:::1]) by kekkonen.fi.intel.com (Postfix) with ESMTP id 947F811FC49; Wed, 20 Dec 2023 12:37:14 +0200 (EET) From: Sakari Ailus To: linux-media@vger.kernel.org Cc: laurent.pinchart@ideasonboard.com, Hans Verkuil Subject: [PATCH v2 01/29] Revert "[media] media: fix media devnode ioctl/syscall and unregister race" Date: Wed, 20 Dec 2023 12:36:45 +0200 Message-Id: <20231220103713.113386-2-sakari.ailus@linux.intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20231220103713.113386-1-sakari.ailus@linux.intel.com> References: <20231220103713.113386-1-sakari.ailus@linux.intel.com> Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 This reverts commit 6f0dd24a084a ("[media] media: fix media devnode ioctl/syscall and unregister race"). The commit was part of an original patchset to avoid crashes when an unregistering device is in use. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil --- drivers/media/mc/mc-device.c | 15 +++++++-------- drivers/media/mc/mc-devnode.c | 8 +------- include/media/media-devnode.h | 16 ++-------------- 3 files changed, 10 insertions(+), 29 deletions(-) diff --git a/drivers/media/mc/mc-device.c b/drivers/media/mc/mc-device.c index c0dd4ae57227..6c569ecd4b3d 100644 --- a/drivers/media/mc/mc-device.c +++ b/drivers/media/mc/mc-device.c @@ -741,7 +741,6 @@ int __must_check __media_device_register(struct media_device *mdev, if (ret < 0) { /* devnode free is handled in media_devnode_*() */ mdev->devnode = NULL; - media_devnode_unregister_prepare(devnode); media_devnode_unregister(devnode); return ret; } @@ -797,9 +796,6 @@ void media_device_unregister(struct media_device *mdev) return; } - /* Clear the devnode register bit to avoid races with media dev open */ - media_devnode_unregister_prepare(mdev->devnode); - /* Remove all entities from the media device */ list_for_each_entry_safe(entity, next, &mdev->entities, graph_obj.list) __media_device_unregister_entity(entity); @@ -824,10 +820,13 @@ void media_device_unregister(struct media_device *mdev) dev_dbg(mdev->dev, "Media device unregistered\n"); - device_remove_file(&mdev->devnode->dev, &dev_attr_model); - media_devnode_unregister(mdev->devnode); - /* devnode free is handled in media_devnode_*() */ - mdev->devnode = NULL; + /* Check if mdev devnode was registered */ + if (media_devnode_is_registered(mdev->devnode)) { + device_remove_file(&mdev->devnode->dev, &dev_attr_model); + media_devnode_unregister(mdev->devnode); + /* devnode free is handled in media_devnode_*() */ + mdev->devnode = NULL; + } } EXPORT_SYMBOL_GPL(media_device_unregister); diff --git a/drivers/media/mc/mc-devnode.c b/drivers/media/mc/mc-devnode.c index 680fbb3a9340..0ab33214d243 100644 --- a/drivers/media/mc/mc-devnode.c +++ b/drivers/media/mc/mc-devnode.c @@ -267,7 +267,7 @@ int __must_check media_devnode_register(struct media_device *mdev, return ret; } -void media_devnode_unregister_prepare(struct media_devnode *devnode) +void media_devnode_unregister(struct media_devnode *devnode) { /* Check if devnode was ever registered at all */ if (!media_devnode_is_registered(devnode)) @@ -275,12 +275,6 @@ void media_devnode_unregister_prepare(struct media_devnode *devnode) mutex_lock(&media_devnode_lock); clear_bit(MEDIA_FLAG_REGISTERED, &devnode->flags); - mutex_unlock(&media_devnode_lock); -} - -void media_devnode_unregister(struct media_devnode *devnode) -{ - mutex_lock(&media_devnode_lock); /* Delete the cdev on this minor as well */ cdev_device_del(&devnode->cdev, &devnode->dev); devnode->media_dev = NULL; diff --git a/include/media/media-devnode.h b/include/media/media-devnode.h index d27c1c646c28..46f0d3ae44d1 100644 --- a/include/media/media-devnode.h +++ b/include/media/media-devnode.h @@ -115,19 +115,6 @@ int __must_check media_devnode_register(struct media_device *mdev, struct media_devnode *devnode, struct module *owner); -/** - * media_devnode_unregister_prepare - clear the media device node register bit - * @devnode: the device node to prepare for unregister - * - * This clears the passed device register bit. Future open calls will be met - * with errors. Should be called before media_devnode_unregister() to avoid - * races with unregister and device file open calls. - * - * This function can safely be called if the device node has never been - * registered or has already been unregistered. - */ -void media_devnode_unregister_prepare(struct media_devnode *devnode); - /** * media_devnode_unregister - unregister a media device node * @devnode: the device node to unregister @@ -135,7 +122,8 @@ void media_devnode_unregister_prepare(struct media_devnode *devnode); * This unregisters the passed device. Future open calls will be met with * errors. * - * Should be called after media_devnode_unregister_prepare() + * This function can safely be called if the device node has never been + * registered or has already been unregistered. */ void media_devnode_unregister(struct media_devnode *devnode); From patchwork Wed Dec 20 10:36:48 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sakari Ailus X-Patchwork-Id: 756745 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 67229208CE for ; Wed, 20 Dec 2023 10:37:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="nvw8XPe9" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1703068642; x=1734604642; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=zfyjOPPGPExsCBpco+FV+gtpUcFP8ASz6xiOXmFUrI0=; b=nvw8XPe9B4o9rjD1PI3Fd/pdpnxTD/zsSTJNuojgGO+6PwvXWdv9rQQC tDTUYsko5YAErWDkYVzkZy5mJkRM0Cxjxnv4nsrtNpaMG13Jaku/54Q+4 pYWZukbJvEJQ++XcMevbIh1DfTBkturl+ycPHQDCY4DzQpYKIJV2N8VXJ e0crfZS6rskrj7GvWkYtAlQAyu6Bx2MiI3eJXhPCs6mDP5XcK34K6NXfS UPaDUe2gTsiEj23+7S2JKhRtnFrqPX33Q3yCHhE5pKobs5NxBz5vOWR/b JapQRwaTyOwAMneznjbFK1jDbUaLfZLibAh6jNeOcFIRgkJpsGOQMvQrD w==; X-IronPort-AV: E=McAfee;i="6600,9927,10929"; a="9174314" X-IronPort-AV: E=Sophos;i="6.04,291,1695711600"; d="scan'208";a="9174314" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2023 02:37:20 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10929"; a="769544233" X-IronPort-AV: E=Sophos;i="6.04,291,1695711600"; d="scan'208";a="769544233" Received: from turnipsi.fi.intel.com (HELO kekkonen.fi.intel.com) ([10.237.72.44]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2023 02:37:19 -0800 Received: from svinhufvud.ger.corp.intel.com (localhost [IPv6:::1]) by kekkonen.fi.intel.com (Postfix) with ESMTP id 55130120706; Wed, 20 Dec 2023 12:37:16 +0200 (EET) From: Sakari Ailus To: linux-media@vger.kernel.org Cc: laurent.pinchart@ideasonboard.com, Hans Verkuil Subject: [PATCH v2 04/29] media: mc: utilize new cdev_device_add helper function Date: Wed, 20 Dec 2023 12:36:48 +0200 Message-Id: <20231220103713.113386-5-sakari.ailus@linux.intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20231220103713.113386-1-sakari.ailus@linux.intel.com> References: <20231220103713.113386-1-sakari.ailus@linux.intel.com> Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Logan Gunthorpe Replace the open coded registration of the cdev and dev with the new device_add_cdev() helper. The helper replaces a common pattern by taking the proper reference against the parent device and adding both the cdev and the device. Signed-off-by: Logan Gunthorpe Acked-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman --- drivers/media/cec/core/cec-core.c | 16 ++++------------ drivers/media/mc/mc-devnode.c | 23 +++++++++-------------- 2 files changed, 13 insertions(+), 26 deletions(-) diff --git a/drivers/media/cec/core/cec-core.c b/drivers/media/cec/core/cec-core.c index 0645e68411fb..15494b46458a 100644 --- a/drivers/media/cec/core/cec-core.c +++ b/drivers/media/cec/core/cec-core.c @@ -137,26 +137,19 @@ static int __must_check cec_devnode_register(struct cec_devnode *devnode, /* Part 2: Initialize and register the character device */ cdev_init(&devnode->cdev, &cec_devnode_fops); - devnode->cdev.kobj.parent = &devnode->dev.kobj; devnode->cdev.owner = owner; kobject_set_name(&devnode->cdev.kobj, "cec%d", devnode->minor); devnode->registered = true; - ret = cdev_add(&devnode->cdev, devnode->dev.devt, 1); - if (ret < 0) { - pr_err("%s: cdev_add failed\n", __func__); + ret = cdev_device_add(&devnode->cdev, &devnode->dev); + if (ret) { + pr_err("%s: cdev_device_add failed\n", __func__); devnode->registered = false; goto clr_bit; } - ret = device_add(&devnode->dev); - if (ret) - goto cdev_del; - return 0; -cdev_del: - cdev_del(&devnode->cdev); clr_bit: mutex_lock(&cec_devnode_lock); clear_bit(devnode->minor, cec_devnode_nums); @@ -202,8 +195,7 @@ static void cec_devnode_unregister(struct cec_adapter *adap) cec_adap_enable(adap); mutex_unlock(&adap->lock); - device_del(&devnode->dev); - cdev_del(&devnode->cdev); + cdev_device_del(&devnode->cdev, &devnode->dev); put_device(&devnode->dev); } diff --git a/drivers/media/mc/mc-devnode.c b/drivers/media/mc/mc-devnode.c index 1e1792c3ae3f..fabcd646679b 100644 --- a/drivers/media/mc/mc-devnode.c +++ b/drivers/media/mc/mc-devnode.c @@ -232,29 +232,24 @@ int __must_check media_devnode_register(struct media_device *mdev, devnode->minor = minor; devnode->media_dev = mdev; - /* Part 2: Initialize and register the character device */ + /* Part 2: Initialize the media and character devices */ cdev_init(&devnode->cdev, &media_devnode_fops); devnode->cdev.owner = owner; kobject_set_name(&devnode->cdev.kobj, "media%d", devnode->minor); - ret = cdev_add(&devnode->cdev, MKDEV(MAJOR(media_dev_t), - devnode->minor), 1); - if (ret < 0) { - pr_err("%s: cdev_add failed\n", __func__); - goto error; - } - - /* Part 3: Register the media device */ devnode->dev.bus = &media_bus_type; devnode->dev.devt = MKDEV(MAJOR(media_dev_t), devnode->minor); devnode->dev.release = media_devnode_release; if (devnode->parent) devnode->dev.parent = devnode->parent; dev_set_name(&devnode->dev, "media%d", devnode->minor); - ret = device_register(&devnode->dev); + device_initialize(&devnode->dev); + + /* Part 3: Add the media and character devices */ + ret = cdev_device_add(&devnode->cdev, &devnode->dev); if (ret < 0) { - pr_err("%s: device_register failed\n", __func__); - goto error; + pr_err("%s: cdev_device_add failed\n", __func__); + goto cdev_add_error; } /* Part 4: Activate this minor. The char device can now be used. */ @@ -262,9 +257,9 @@ int __must_check media_devnode_register(struct media_device *mdev, return 0; -error: +cdev_add_error: mutex_lock(&media_devnode_lock); - cdev_del(&devnode->cdev); + cdev_device_del(&devnode->cdev, &devnode->dev); clear_bit(devnode->minor, media_devnode_nums); mutex_unlock(&media_devnode_lock); From patchwork Wed Dec 20 10:36:50 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sakari Ailus X-Patchwork-Id: 756746 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 78B0620B1A for ; Wed, 20 Dec 2023 10:37:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="bdWa3xPq" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1703068643; x=1734604643; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=PhOuyz9RnP0CM07VW5m7jpNcMxocyOzQCNfex26x3Ig=; b=bdWa3xPqQahrtOv08oQRukc0CnqwSfUJVeCB7XLkt2nxKy/laftu7HcE 6xo90iz8XlnQ5fnBqj/mXQT1aAXmrg85aplWugt/5M/AKYa7Mog3QWHSu wmgZzDPl9b00vwc6GwqyxsQBmp6kLX1nfN7YUm2w+1vkiRpFkx5dsr1R5 oNF/jmOPY0+XDb71X1cRFebenfazWj/g8YaZdVZ0UMISfQDLRU58uX9vY 2le6uUH6bLh8JsaABqSpprMnbHlhe4lzZvkfVv7OhhCN6V6g9Qfpi0Q2i DgrIiLHM7NjpeYU08sMq/ZRgHE389YSmeSJ/tIsGGoS80wH8hbMW1NMLf g==; X-IronPort-AV: E=McAfee;i="6600,9927,10929"; a="9174319" X-IronPort-AV: E=Sophos;i="6.04,291,1695711600"; d="scan'208";a="9174319" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2023 02:37:22 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10929"; a="769544239" X-IronPort-AV: E=Sophos;i="6.04,291,1695711600"; d="scan'208";a="769544239" Received: from turnipsi.fi.intel.com (HELO kekkonen.fi.intel.com) ([10.237.72.44]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2023 02:37:20 -0800 Received: from svinhufvud.ger.corp.intel.com (localhost [IPv6:::1]) by kekkonen.fi.intel.com (Postfix) with ESMTP id 9685F12098A; Wed, 20 Dec 2023 12:37:17 +0200 (EET) From: Sakari Ailus To: linux-media@vger.kernel.org Cc: laurent.pinchart@ideasonboard.com, Hans Verkuil Subject: [PATCH v2 06/29] Revert "[media] media-device: dynamically allocate struct media_devnode" Date: Wed, 20 Dec 2023 12:36:50 +0200 Message-Id: <20231220103713.113386-7-sakari.ailus@linux.intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20231220103713.113386-1-sakari.ailus@linux.intel.com> References: <20231220103713.113386-1-sakari.ailus@linux.intel.com> Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 This reverts commit a087ce704b80 ("[media] media-device: dynamically allocate struct media_devnode"). The commit was part of an original patchset to avoid crashes when an unregistering device is in use. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil --- drivers/media/mc/mc-device.c | 44 +++++++-------------- drivers/media/mc/mc-devnode.c | 7 +--- drivers/media/usb/au0828/au0828-core.c | 4 +- drivers/media/usb/uvc/uvc_driver.c | 2 +- drivers/staging/media/sunxi/cedrus/cedrus.c | 2 +- include/media/media-device.h | 5 ++- include/media/media-devnode.h | 15 +------ 7 files changed, 25 insertions(+), 54 deletions(-) diff --git a/drivers/media/mc/mc-device.c b/drivers/media/mc/mc-device.c index 4772a7f55112..d4553a3705f5 100644 --- a/drivers/media/mc/mc-device.c +++ b/drivers/media/mc/mc-device.c @@ -435,7 +435,7 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd, unsigned long __arg) { struct media_devnode *devnode = media_devnode_data(filp); - struct media_device *dev = devnode->media_dev; + struct media_device *dev = to_media_device(devnode); const struct media_ioctl_info *info; void __user *arg = (void __user *)__arg; char __karg[256], *karg = __karg; @@ -519,7 +519,7 @@ static long media_device_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct media_devnode *devnode = media_devnode_data(filp); - struct media_device *dev = devnode->media_dev; + struct media_device *dev = to_media_device(devnode); long ret; switch (cmd) { @@ -555,8 +555,7 @@ static const struct media_file_operations media_device_fops = { static ssize_t model_show(struct device *cd, struct device_attribute *attr, char *buf) { - struct media_devnode *devnode = to_media_devnode(cd); - struct media_device *mdev = devnode->media_dev; + struct media_device *mdev = to_media_device(to_media_devnode(cd)); return sprintf(buf, "%.*s\n", (int)sizeof(mdev->model), mdev->model); } @@ -714,34 +713,23 @@ EXPORT_SYMBOL_GPL(media_device_cleanup); int __must_check __media_device_register(struct media_device *mdev, struct module *owner) { - struct media_devnode *devnode; int ret; - devnode = kzalloc(sizeof(*devnode), GFP_KERNEL); - if (!devnode) - return -ENOMEM; - /* Register the device node. */ - mdev->devnode = devnode; - devnode->fops = &media_device_fops; - devnode->parent = mdev->dev; - devnode->release = media_device_release; + mdev->devnode.fops = &media_device_fops; + mdev->devnode.parent = mdev->dev; + mdev->devnode.release = media_device_release; /* Set version 0 to indicate user-space that the graph is static */ mdev->topology_version = 0; - ret = media_devnode_register(mdev, devnode, owner); - if (ret < 0) { - mdev->devnode = NULL; - kfree(devnode); + ret = media_devnode_register(&mdev->devnode, owner); + if (ret < 0) return ret; - } - ret = device_create_file(&devnode->dev, &dev_attr_model); + ret = device_create_file(&mdev->devnode.dev, &dev_attr_model); if (ret < 0) { - mdev->devnode = NULL; - media_devnode_unregister(devnode); - kfree(devnode); + media_devnode_unregister(&mdev->devnode); return ret; } @@ -791,7 +779,7 @@ void media_device_unregister(struct media_device *mdev) mutex_lock(&mdev->graph_mutex); /* Check if mdev was ever registered at all */ - if (!media_devnode_is_registered(mdev->devnode)) { + if (!media_devnode_is_registered(&mdev->devnode)) { mutex_unlock(&mdev->graph_mutex); return; } @@ -818,13 +806,9 @@ void media_device_unregister(struct media_device *mdev) mutex_unlock(&mdev->graph_mutex); - dev_dbg(mdev->dev, "Media device unregistered\n"); - - /* Check if mdev devnode was registered */ - if (media_devnode_is_registered(mdev->devnode)) { - device_remove_file(&mdev->devnode->dev, &dev_attr_model); - media_devnode_unregister(mdev->devnode); - } + device_remove_file(&mdev->devnode.dev, &dev_attr_model); + dev_dbg(mdev->dev, "Media device unregistering\n"); + media_devnode_unregister(&mdev->devnode); } EXPORT_SYMBOL_GPL(media_device_unregister); diff --git a/drivers/media/mc/mc-devnode.c b/drivers/media/mc/mc-devnode.c index fabcd646679b..ce93ab9be676 100644 --- a/drivers/media/mc/mc-devnode.c +++ b/drivers/media/mc/mc-devnode.c @@ -32,7 +32,6 @@ #include #include -#include #define MEDIA_NUM_DEVICES 256 #define MEDIA_NAME "media" @@ -63,8 +62,6 @@ static void media_devnode_release(struct device *cd) /* Release media_devnode and perform other cleanups as needed. */ if (devnode->release) devnode->release(devnode); - - kfree(devnode); } static struct bus_type media_bus_type = { @@ -210,8 +207,7 @@ static const struct file_operations media_devnode_fops = { .llseek = no_llseek, }; -int __must_check media_devnode_register(struct media_device *mdev, - struct media_devnode *devnode, +int __must_check media_devnode_register(struct media_devnode *devnode, struct module *owner) { int minor; @@ -230,7 +226,6 @@ int __must_check media_devnode_register(struct media_device *mdev, mutex_unlock(&media_devnode_lock); devnode->minor = minor; - devnode->media_dev = mdev; /* Part 2: Initialize the media and character devices */ cdev_init(&devnode->cdev, &media_devnode_fops); diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index 1e246b47766d..4101e12cda5a 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -128,7 +128,7 @@ static void au0828_unregister_media_device(struct au0828_dev *dev) struct media_device *mdev = dev->media_dev; struct media_entity_notify *notify, *nextp; - if (!mdev || !media_devnode_is_registered(mdev->devnode)) + if (!mdev || !media_devnode_is_registered(&mdev->devnode)) return; /* Remove au0828 entity_notify callbacks */ @@ -566,7 +566,7 @@ static int au0828_media_device_register(struct au0828_dev *dev, if (!dev->media_dev) return 0; - if (!media_devnode_is_registered(dev->media_dev->devnode)) { + if (!media_devnode_is_registered(&dev->media_dev->devnode)) { /* register media device */ ret = media_device_register(dev->media_dev); diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index fe8b251f47e7..1044e13976b5 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -1862,7 +1862,7 @@ static void uvc_delete(struct kref *kref) if (dev->vdev.dev) v4l2_device_unregister(&dev->vdev); #ifdef CONFIG_MEDIA_CONTROLLER - if (media_devnode_is_registered(dev->mdev.devnode)) + if (media_devnode_is_registered(&dev->mdev.devnode)) media_device_unregister(&dev->mdev); media_device_cleanup(&dev->mdev); #endif diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index f52df6836045..f8f678835a4c 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -548,7 +548,7 @@ static void cedrus_remove(struct platform_device *pdev) struct cedrus_dev *dev = platform_get_drvdata(pdev); cancel_delayed_work_sync(&dev->watchdog_work); - if (media_devnode_is_registered(dev->mdev.devnode)) { + if (media_devnode_is_registered(&dev->mdev.devnode)) { media_device_unregister(&dev->mdev); v4l2_m2m_unregister_media_controller(dev->m2m_dev); media_device_cleanup(&dev->mdev); diff --git a/include/media/media-device.h b/include/media/media-device.h index 2c146d0b2b1c..fb0855b217ce 100644 --- a/include/media/media-device.h +++ b/include/media/media-device.h @@ -145,7 +145,7 @@ struct media_device_ops { struct media_device { /* dev->driver_data points to this struct. */ struct device *dev; - struct media_devnode *devnode; + struct media_devnode devnode; char model[32]; char driver_name[32]; @@ -191,6 +191,9 @@ struct usb_device; #define MEDIA_DEV_NOTIFY_PRE_LINK_CH 0 #define MEDIA_DEV_NOTIFY_POST_LINK_CH 1 +/* media_devnode to media_device */ +#define to_media_device(node) container_of(node, struct media_device, devnode) + /** * media_device_init() - Initializes a media device element * diff --git a/include/media/media-devnode.h b/include/media/media-devnode.h index 46f0d3ae44d1..1117d1dfd6bf 100644 --- a/include/media/media-devnode.h +++ b/include/media/media-devnode.h @@ -21,8 +21,6 @@ #include #include -struct media_device; - /* * Flag to mark the media_devnode struct as registered. Drivers must not touch * this flag directly, it will be set and cleared by media_devnode_register and @@ -73,8 +71,6 @@ struct media_file_operations { * before registering the node. */ struct media_devnode { - struct media_device *media_dev; - /* device ops */ const struct media_file_operations *fops; @@ -97,8 +93,7 @@ struct media_devnode { /** * media_devnode_register - register a media device node * - * @mdev: struct media_device we want to register a device node - * @devnode: media device node structure we want to register + * @devnode: struct media_devnode we want to register a device node * @owner: should be filled with %THIS_MODULE * * The registration code assigns minor numbers and registers the new device node @@ -111,8 +106,7 @@ struct media_devnode { * the media_devnode structure is *not* called, so the caller is responsible for * freeing any data. */ -int __must_check media_devnode_register(struct media_device *mdev, - struct media_devnode *devnode, +int __must_check media_devnode_register(struct media_devnode *devnode, struct module *owner); /** @@ -142,14 +136,9 @@ static inline struct media_devnode *media_devnode_data(struct file *filp) * false otherwise. * * @devnode: pointer to struct &media_devnode. - * - * Note: If mdev is NULL, it also returns false. */ static inline int media_devnode_is_registered(struct media_devnode *devnode) { - if (!devnode) - return false; - return test_bit(MEDIA_FLAG_REGISTERED, &devnode->flags); } From patchwork Wed Dec 20 10:36:51 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sakari Ailus X-Patchwork-Id: 756744 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4009E20DCC for ; Wed, 20 Dec 2023 10:37:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="jq8mg5r0" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1703068645; x=1734604645; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=T/C9ZAO8qLneaLiBytVbO1mPwOAigpXoR7B3eXx1GyA=; b=jq8mg5r0ppTdTFAbzsAUR0YdYOal4uL3jAJOwPFJ3zioGMDLmidEtFjP QoGyFVPTUm61acaXjH/KNe4bXFc7VR8JyHEH2iRqsm5XhkWkX/9licHSW XG2SjYkw9jouNOODPOMZ2yjkqji4WYSWLCDgR8g2Lh+wACWO5EK981UlW C/6qQK15n3x0NICRKqjts2FVDbH5KMZjtnaf9h7wcTUw+H+AVsOD3pDod xPu7Txx2wwNVbN3M4DaSg+/66qfitq8iBLCa4eTpWzHVd5Afq8DSoGm+1 pWX9uRZ+qexi4ouvT8lZ78klA9F/O84FP3EKofq+QFs4m939nj7jokPex A==; X-IronPort-AV: E=McAfee;i="6600,9927,10929"; a="9174330" X-IronPort-AV: E=Sophos;i="6.04,291,1695711600"; d="scan'208";a="9174330" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2023 02:37:23 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10929"; a="769544244" X-IronPort-AV: E=Sophos;i="6.04,291,1695711600"; d="scan'208";a="769544244" Received: from turnipsi.fi.intel.com (HELO kekkonen.fi.intel.com) ([10.237.72.44]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2023 02:37:21 -0800 Received: from svinhufvud.ger.corp.intel.com (localhost [IPv6:::1]) by kekkonen.fi.intel.com (Postfix) with ESMTP id 68119120A70; Wed, 20 Dec 2023 12:37:18 +0200 (EET) From: Sakari Ailus To: linux-media@vger.kernel.org Cc: laurent.pinchart@ideasonboard.com, Hans Verkuil Subject: [PATCH v2 07/29] media: uvcvideo: Refactor teardown of uvc on USB disconnect Date: Wed, 20 Dec 2023 12:36:51 +0200 Message-Id: <20231220103713.113386-8-sakari.ailus@linux.intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20231220103713.113386-1-sakari.ailus@linux.intel.com> References: <20231220103713.113386-1-sakari.ailus@linux.intel.com> Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Daniel Axtens Currently, disconnecting a USB webcam while it is in use prints out a number of warnings, such as: WARNING: CPU: 2 PID: 3118 at /build/linux-ezBi1T/linux-4.8.0/fs/sysfs/group.c:237 sysfs_remove_group+0x8b/0x90 sysfs group ffffffffa7cd0780 not found for kobject 'event13' This has been noticed before. [0] This is because of the order in which things are torn down. If there are no streams active during a USB disconnect: - uvc_disconnect() is invoked via device_del() through the bus notifier mechanism. - this calls uvc_unregister_video(). - uvc_unregister_video() unregisters the video device for each stream, - because there are no streams open, it calls uvc_delete() - uvc_delete() calls uvc_status_cleanup(), which cleans up the status input device. - uvc_delete() calls media_device_unregister(), which cleans up the media device - uvc_delete(), uvc_unregister_video() and uvc_disconnect() all return, and we end up back in device_del(). - device_del() then cleans up the sysfs folder for the camera with dpm_sysfs_remove(). Because uvc_status_cleanup() and media_device_unregister() have already been called, this all works nicely. If, on the other hand, there *are* streams active during a USB disconnect: - uvc_disconnect() is invoked - this calls uvc_unregister_video() - uvc_unregister_video() unregisters the video device for each stream, - uvc_unregister_video() and uvc_disconnect() return, and we end up back in device_del(). - device_del() then cleans up the sysfs folder for the camera with dpm_sysfs_remove(). Because the status input device and the media device are children of the USB device, this also deletes their sysfs folders. - Sometime later, the final stream is closed, invoking uvc_release(). - uvc_release() calls uvc_delete() - uvc_delete() calls uvc_status_cleanup(), which cleans up the status input device. Because the sysfs directory has already been removed, this causes a WARNing. - uvc_delete() calls media_device_unregister(), which cleans up the media device. Because the sysfs directory has already been removed, this causes another WARNing. To fix this, we need to make sure the devices are always unregistered before the end of uvc_disconnect(). To this, move the unregistration into the disconnect path: - split uvc_status_cleanup() into two parts, one on disconnect that unregisters and one on delete that frees. - move v4l2_device_unregister() and media_device_unregister() into the disconnect path. [0]: https://lkml.org/lkml/2016/12/8/657 [Renamed uvc_input_cleanup() to uvc_input_unregister()] Signed-off-by: Daniel Axtens Acked-by: Greg Kroah-Hartman Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab [Sakari Ailus: Rebase on patch Revert "[media] media-device: dynamically allocate struct media_devnode"] Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil --- drivers/media/usb/uvc/uvc_driver.c | 13 +++++++++---- drivers/media/usb/uvc/uvc_status.c | 12 ++++++++---- drivers/media/usb/uvc/uvcvideo.h | 1 + 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 1044e13976b5..7add92f45329 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -1859,11 +1859,7 @@ static void uvc_delete(struct kref *kref) usb_put_intf(dev->intf); usb_put_dev(dev->udev); - if (dev->vdev.dev) - v4l2_device_unregister(&dev->vdev); #ifdef CONFIG_MEDIA_CONTROLLER - if (media_devnode_is_registered(&dev->mdev.devnode)) - media_device_unregister(&dev->mdev); media_device_cleanup(&dev->mdev); #endif @@ -1920,6 +1916,15 @@ static void uvc_unregister_video(struct uvc_device *dev) uvc_debugfs_cleanup_stream(stream); } + + uvc_status_unregister(dev); + + if (dev->vdev.dev) + v4l2_device_unregister(&dev->vdev); +#ifdef CONFIG_MEDIA_CONTROLLER + if (media_devnode_is_registered(&dev->mdev.devnode)) + media_device_unregister(&dev->mdev); +#endif } int uvc_register_video_device(struct uvc_device *dev, diff --git a/drivers/media/usb/uvc/uvc_status.c b/drivers/media/usb/uvc/uvc_status.c index 015be0886801..a78a88c710e2 100644 --- a/drivers/media/usb/uvc/uvc_status.c +++ b/drivers/media/usb/uvc/uvc_status.c @@ -73,7 +73,7 @@ static int uvc_input_init(struct uvc_device *dev) return ret; } -static void uvc_input_cleanup(struct uvc_device *dev) +static void uvc_input_unregister(struct uvc_device *dev) { if (dev->input) input_unregister_device(dev->input); @@ -90,7 +90,7 @@ static void uvc_input_report_key(struct uvc_device *dev, unsigned int code, #else #define uvc_input_init(dev) -#define uvc_input_cleanup(dev) +#define uvc_input_unregister(dev) #define uvc_input_report_key(dev, code, value) #endif /* CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV */ @@ -290,12 +290,16 @@ int uvc_status_init(struct uvc_device *dev) return 0; } -void uvc_status_cleanup(struct uvc_device *dev) +void uvc_status_unregister(struct uvc_device *dev) { usb_kill_urb(dev->int_urb); + uvc_input_unregister(dev); +} + +void uvc_status_cleanup(struct uvc_device *dev) +{ usb_free_urb(dev->int_urb); kfree(dev->status); - uvc_input_cleanup(dev); } int uvc_status_start(struct uvc_device *dev, gfp_t flags) diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index ab8de60f5de2..6fb0a78b1b00 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -742,6 +742,7 @@ int uvc_register_video_device(struct uvc_device *dev, /* Status */ int uvc_status_init(struct uvc_device *dev); +void uvc_status_unregister(struct uvc_device *dev); void uvc_status_cleanup(struct uvc_device *dev); int uvc_status_start(struct uvc_device *dev, gfp_t flags); void uvc_status_stop(struct uvc_device *dev); From patchwork Wed Dec 20 10:36:54 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sakari Ailus X-Patchwork-Id: 756743 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6783220DF3 for ; Wed, 20 Dec 2023 10:37:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="RkTbjYp+" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1703068646; x=1734604646; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=05/GurQC+tFTFg0EilvY/mjumAa9KUU6C9I+HxauEVg=; b=RkTbjYp+x0HZOB9kwu/p8s3P33KvqvDhOs4PZtjO2kXwctQbpuUPTtB7 vnioeZnuRU5KlehkPR9ttlacqE2Wmv3r32bvCeWKy+KUGz0YE1F/Ssq1f UDWThwHHxzqd+kVLTXq7qFV3ap4KLYgGZulJDCFGP/ahUOjLRniURpYSB CwqYZgeG5M5gCVuOa5Ukhzp0Gz/D919zpf0npSzjorj+Mw9LAxtqA1xAC 17r8AQC9r+NHy0DLwXznTakty+Aj/QPGdQv+icHJd43nXn2IrTGRp/dBP X2oY2FCpQjrT4Sfh3oj4oUDvkimHYOVAsTwhfj7V2Ht5L8PH70w1lmh/J A==; X-IronPort-AV: E=McAfee;i="6600,9927,10929"; a="9174336" X-IronPort-AV: E=Sophos;i="6.04,291,1695711600"; d="scan'208";a="9174336" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2023 02:37:24 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10929"; a="769544250" X-IronPort-AV: E=Sophos;i="6.04,291,1695711600"; d="scan'208";a="769544250" Received: from turnipsi.fi.intel.com (HELO kekkonen.fi.intel.com) ([10.237.72.44]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2023 02:37:23 -0800 Received: from svinhufvud.ger.corp.intel.com (localhost [IPv6:::1]) by kekkonen.fi.intel.com (Postfix) with ESMTP id 6F8C61201D0; Wed, 20 Dec 2023 12:37:20 +0200 (EET) From: Sakari Ailus To: linux-media@vger.kernel.org Cc: laurent.pinchart@ideasonboard.com, Hans Verkuil Subject: [PATCH v2 10/29] media: mc: Delete character device early Date: Wed, 20 Dec 2023 12:36:54 +0200 Message-Id: <20231220103713.113386-11-sakari.ailus@linux.intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20231220103713.113386-1-sakari.ailus@linux.intel.com> References: <20231220103713.113386-1-sakari.ailus@linux.intel.com> Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The parent of the character device related to the media devnode is the media devnode. Thus the character device needs to be released before the media devnode's release function. Move it to unregistering of the media devnode, which mirrors adding the character device in conjunction with registering the media devnode. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Reviewed-by: Laurent Pinchart --- drivers/media/mc/mc-devnode.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/mc/mc-devnode.c b/drivers/media/mc/mc-devnode.c index 7e22938dfd81..8bc7450ac144 100644 --- a/drivers/media/mc/mc-devnode.c +++ b/drivers/media/mc/mc-devnode.c @@ -51,9 +51,6 @@ static void media_devnode_release(struct device *cd) mutex_lock(&media_devnode_lock); - /* Delete the cdev on this minor as well */ - cdev_del(&devnode->cdev); - /* Mark device node number as free */ clear_bit(devnode->minor, media_devnode_nums); @@ -270,6 +267,7 @@ void media_devnode_unregister(struct media_devnode *devnode) clear_bit(MEDIA_FLAG_REGISTERED, &devnode->flags); mutex_unlock(&media_devnode_lock); + cdev_del(&devnode->cdev); device_unregister(&devnode->dev); } From patchwork Wed Dec 20 10:36:56 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sakari Ailus X-Patchwork-Id: 756742 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 82D70210FC for ; Wed, 20 Dec 2023 10:37:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="PRE6j4vF" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1703068647; x=1734604647; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=HOzRLelRw5VDilK37nbbPR6Q6DkmhJ5MpT0c9fWu5wo=; b=PRE6j4vFfZjgWAGxbKAcDBwNB9xsC7W5D5ClwjV6g3ELDyTe6dR+F3O9 sOmsNL9ZftYagN+/nnhvU57CaBG+DblOyqfrtRKwk/1ZM5UblErOXta7I XsGeD6MepkwUJJW2zio/qAP+74KTM3nfZcHFyv9whAGcorYTUIcRYUP0w 1feaw0nQk6NvO0JKk+x4Q8mBjP++QfM9anoaKJbNa6D+pSm/6nlhqZId+ EAY39s95fRtDYrKdvPeytMWKHaSTjmncR8E4ZH9wAyyrIyRLOCw9NdNZC hK9CnszZ/5S9qj1PFVBeg0nzEdnoDhnH3AZUtN9CLcDU9mmfgdwYMj75u g==; X-IronPort-AV: E=McAfee;i="6600,9927,10929"; a="9174342" X-IronPort-AV: E=Sophos;i="6.04,291,1695711600"; d="scan'208";a="9174342" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2023 02:37:26 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10929"; a="769544252" X-IronPort-AV: E=Sophos;i="6.04,291,1695711600"; d="scan'208";a="769544252" Received: from turnipsi.fi.intel.com (HELO kekkonen.fi.intel.com) ([10.237.72.44]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2023 02:37:24 -0800 Received: from svinhufvud.ger.corp.intel.com (localhost [IPv6:::1]) by kekkonen.fi.intel.com (Postfix) with ESMTP id B9AB3120706; Wed, 20 Dec 2023 12:37:21 +0200 (EET) From: Sakari Ailus To: linux-media@vger.kernel.org Cc: laurent.pinchart@ideasonboard.com, Hans Verkuil Subject: [PATCH v2 12/29] media: mc: Shuffle functions around Date: Wed, 20 Dec 2023 12:36:56 +0200 Message-Id: <20231220103713.113386-13-sakari.ailus@linux.intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20231220103713.113386-1-sakari.ailus@linux.intel.com> References: <20231220103713.113386-1-sakari.ailus@linux.intel.com> Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 As the call paths of the functions in question will change, move them around in anticipation of that. No other changes. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Reviewed-by: Laurent Pinchart --- drivers/media/mc/mc-device.c | 54 ++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/drivers/media/mc/mc-device.c b/drivers/media/mc/mc-device.c index ebf037cd5f4a..44685ab6a450 100644 --- a/drivers/media/mc/mc-device.c +++ b/drivers/media/mc/mc-device.c @@ -673,6 +673,33 @@ void media_device_unregister_entity(struct media_entity *entity) } EXPORT_SYMBOL_GPL(media_device_unregister_entity); +void media_device_register_entity_notify(struct media_device *mdev, + struct media_entity_notify *nptr) +{ + mutex_lock(&mdev->graph_mutex); + list_add_tail(&nptr->list, &mdev->entity_notify); + mutex_unlock(&mdev->graph_mutex); +} +EXPORT_SYMBOL_GPL(media_device_register_entity_notify); + +/* + * Note: Should be called with mdev->lock held. + */ +static void __media_device_unregister_entity_notify(struct media_device *mdev, + struct media_entity_notify *nptr) +{ + list_del(&nptr->list); +} + +void media_device_unregister_entity_notify(struct media_device *mdev, + struct media_entity_notify *nptr) +{ + mutex_lock(&mdev->graph_mutex); + __media_device_unregister_entity_notify(mdev, nptr); + mutex_unlock(&mdev->graph_mutex); +} +EXPORT_SYMBOL_GPL(media_device_unregister_entity_notify); + void media_device_init(struct media_device *mdev) { INIT_LIST_HEAD(&mdev->entities); @@ -740,33 +767,6 @@ int __must_check __media_device_register(struct media_device *mdev, } EXPORT_SYMBOL_GPL(__media_device_register); -void media_device_register_entity_notify(struct media_device *mdev, - struct media_entity_notify *nptr) -{ - mutex_lock(&mdev->graph_mutex); - list_add_tail(&nptr->list, &mdev->entity_notify); - mutex_unlock(&mdev->graph_mutex); -} -EXPORT_SYMBOL_GPL(media_device_register_entity_notify); - -/* - * Note: Should be called with mdev->lock held. - */ -static void __media_device_unregister_entity_notify(struct media_device *mdev, - struct media_entity_notify *nptr) -{ - list_del(&nptr->list); -} - -void media_device_unregister_entity_notify(struct media_device *mdev, - struct media_entity_notify *nptr) -{ - mutex_lock(&mdev->graph_mutex); - __media_device_unregister_entity_notify(mdev, nptr); - mutex_unlock(&mdev->graph_mutex); -} -EXPORT_SYMBOL_GPL(media_device_unregister_entity_notify); - void media_device_unregister(struct media_device *mdev) { struct media_entity *entity; From patchwork Wed Dec 20 10:36:58 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sakari Ailus X-Patchwork-Id: 756741 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4580821116 for ; Wed, 20 Dec 2023 10:37:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="IW2QOBPH" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1703068648; x=1734604648; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=f4QZYuk5GOjZevZxAHm7nfSqVvf3WIo8y/0km/Uo4k4=; b=IW2QOBPHRqEHrMVCxHvxvj8SWiwG+GQekwKlwAeKSjOIl8IPPB3GyOfF VQH0MMU7SDurNOO3QJhoagcbjVCkKhGX/OSZ18qYMnbFpOX1QY/8OdI4+ 5kk9hKpJVyoPm+FdXO6QwLQgOohKkM1ddPQbKKBLrSNmVDpBv+Vuirysx AgFi/X/HWu6hsHVmwtfDlGzarek+qFtguhoMxGXAkECAspebIi//u4oAm GPvZL+N/Cq0W/bsDh1SXYVz804/DnsHiOm3n3LUdUwAE30vCjJRdL+NES 47MFmHQTUj6dDyyvIY0rI3imId+54CcO3w/2ccV2AKj9jQ7D8MyaTPvwz A==; X-IronPort-AV: E=McAfee;i="6600,9927,10929"; a="9174351" X-IronPort-AV: E=Sophos;i="6.04,291,1695711600"; d="scan'208";a="9174351" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2023 02:37:27 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10929"; a="769544257" X-IronPort-AV: E=Sophos;i="6.04,291,1695711600"; d="scan'208";a="769544257" Received: from turnipsi.fi.intel.com (HELO kekkonen.fi.intel.com) ([10.237.72.44]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2023 02:37:25 -0800 Received: from svinhufvud.ger.corp.intel.com (localhost [IPv6:::1]) by kekkonen.fi.intel.com (Postfix) with ESMTP id 2E6AD11FB5E; Wed, 20 Dec 2023 12:37:23 +0200 (EET) From: Sakari Ailus To: linux-media@vger.kernel.org Cc: laurent.pinchart@ideasonboard.com, Hans Verkuil Subject: [PATCH v2 14/29] media: mc: Refactor media devnode minor clearing Date: Wed, 20 Dec 2023 12:36:58 +0200 Message-Id: <20231220103713.113386-15-sakari.ailus@linux.intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20231220103713.113386-1-sakari.ailus@linux.intel.com> References: <20231220103713.113386-1-sakari.ailus@linux.intel.com> Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Refactor clearing media devnode minor bit in media devnode bitmap. Note that number is used instead of struct media_devnode as argument since the minor number will also be stored in a different structure soon. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Reviewed-by: Laurent Pinchart --- drivers/media/mc/mc-devnode.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/media/mc/mc-devnode.c b/drivers/media/mc/mc-devnode.c index 7b17419050fb..717408791a7c 100644 --- a/drivers/media/mc/mc-devnode.c +++ b/drivers/media/mc/mc-devnode.c @@ -44,17 +44,22 @@ static dev_t media_dev_t; static DEFINE_MUTEX(media_devnode_lock); static DECLARE_BITMAP(media_devnode_nums, MEDIA_NUM_DEVICES); -/* Called when the last user of the media device exits. */ -static void media_devnode_release(struct device *cd) +static void media_devnode_free_minor(unsigned int minor) { - struct media_devnode *devnode = to_media_devnode(cd); - mutex_lock(&media_devnode_lock); /* Mark device node number as free */ - clear_bit(devnode->minor, media_devnode_nums); + clear_bit(minor, media_devnode_nums); mutex_unlock(&media_devnode_lock); +} + +/* Called when the last user of the media device exits. */ +static void media_devnode_release(struct device *cd) +{ + struct media_devnode *devnode = to_media_devnode(cd); + + media_devnode_free_minor(devnode->minor); /* Release media_devnode and perform other cleanups as needed. */ if (devnode->release) @@ -254,9 +259,7 @@ int __must_check media_devnode_register(struct media_devnode *devnode, return 0; cdev_add_error: - mutex_lock(&media_devnode_lock); - clear_bit(devnode->minor, media_devnode_nums); - mutex_unlock(&media_devnode_lock); + media_devnode_free_minor(devnode->minor); return ret; } From patchwork Wed Dec 20 10:37:00 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sakari Ailus X-Patchwork-Id: 756740 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1565C2134A for ; Wed, 20 Dec 2023 10:37:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="V6JzCyEM" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1703068649; x=1734604649; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=AuhiUd0lvh2AZG/DF52hVKm1+VmJk7dFMC744uMD+rw=; b=V6JzCyEMyb7KIjdAekAi2Sl4Gdj21qllg0KDgHbgot0hahDE7HaqpFEC 1XlKzOsXGhY71Wp2RHfs664tNrIjfcw0ja4bLpqEHld7v2N8TClNfwTAi gVOXW8/iB2ZIHNrx6RRenLOVLVXNAcvdowL0O1+s8DXRldadm62RwdOar RzMZtcODlt76BbGy+apf2LDDmhjbEJyyZnJ5uOLy16MtGwa1fPBkC5Qxi I0gTy++Ho/qFgIoi7GdE6EN8XwHITDjKAiaMBJTkYKw7vfifdtR/UKhwy xDM6xG3wkC9TTIBaNY7OmnGd4+2+FZLp/q4rDi2UVSi88eqfAxnvEbFR/ Q==; X-IronPort-AV: E=McAfee;i="6600,9927,10929"; a="9174359" X-IronPort-AV: E=Sophos;i="6.04,291,1695711600"; d="scan'208";a="9174359" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2023 02:37:28 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10929"; a="769544259" X-IronPort-AV: E=Sophos;i="6.04,291,1695711600"; d="scan'208";a="769544259" Received: from turnipsi.fi.intel.com (HELO kekkonen.fi.intel.com) ([10.237.72.44]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2023 02:37:26 -0800 Received: from svinhufvud.ger.corp.intel.com (localhost [IPv6:::1]) by kekkonen.fi.intel.com (Postfix) with ESMTP id 6EA6E11FC49; Wed, 20 Dec 2023 12:37:24 +0200 (EET) From: Sakari Ailus To: linux-media@vger.kernel.org Cc: laurent.pinchart@ideasonboard.com, Hans Verkuil Subject: [PATCH v2 16/29] media: mc: Refcount the media device Date: Wed, 20 Dec 2023 12:37:00 +0200 Message-Id: <20231220103713.113386-17-sakari.ailus@linux.intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20231220103713.113386-1-sakari.ailus@linux.intel.com> References: <20231220103713.113386-1-sakari.ailus@linux.intel.com> Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 As the struct media_device embeds struct media_devnode, the lifetime of that object must be that same than that of the media_device. References are obtained by media_device_get() and released by media_device_put(). In order to use refcounting, the driver must set the release callback before calling media_device_init() on the media device. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil --- drivers/media/mc/mc-device.c | 36 +++++++++++++++++++++++++++++------ drivers/media/mc/mc-devnode.c | 6 +++++- include/media/media-device.h | 28 +++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 7 deletions(-) diff --git a/drivers/media/mc/mc-device.c b/drivers/media/mc/mc-device.c index e6ac9b066524..bbc233e726d2 100644 --- a/drivers/media/mc/mc-device.c +++ b/drivers/media/mc/mc-device.c @@ -700,6 +700,31 @@ void media_device_unregister_entity_notify(struct media_device *mdev, } EXPORT_SYMBOL_GPL(media_device_unregister_entity_notify); +static void __media_device_release(struct media_device *mdev) +{ + dev_dbg(mdev->dev, "Media device released\n"); + + ida_destroy(&mdev->entity_internal_idx); + mdev->entity_internal_idx_max = 0; + media_graph_walk_cleanup(&mdev->pm_count_walk); + mutex_destroy(&mdev->graph_mutex); + mutex_destroy(&mdev->req_queue_mutex); +} + +static void media_device_release(struct media_devnode *devnode) +{ + struct media_device *mdev = to_media_device(devnode); + + if (mdev->ops && mdev->ops->release) { + /* + * If release op isn't set, __media_device_release() is called + * via media_device_cleanup(). + */ + __media_device_release(mdev); + mdev->ops->release(mdev); + } +} + void media_device_init(struct media_device *mdev) { INIT_LIST_HEAD(&mdev->entities); @@ -712,6 +737,8 @@ void media_device_init(struct media_device *mdev) mutex_init(&mdev->graph_mutex); ida_init(&mdev->entity_internal_idx); atomic_set(&mdev->request_id, 0); + + mdev->devnode.release = media_device_release; media_devnode_init(&mdev->devnode); if (!*mdev->bus_info) @@ -724,12 +751,9 @@ EXPORT_SYMBOL_GPL(media_device_init); void media_device_cleanup(struct media_device *mdev) { - ida_destroy(&mdev->entity_internal_idx); - mdev->entity_internal_idx_max = 0; - media_graph_walk_cleanup(&mdev->pm_count_walk); - mutex_destroy(&mdev->graph_mutex); - mutex_destroy(&mdev->req_queue_mutex); - put_device(&mdev->devnode.dev); + WARN_ON(mdev->ops && mdev->ops->release); + __media_device_release(mdev); + media_device_put(mdev); } EXPORT_SYMBOL_GPL(media_device_cleanup); diff --git a/drivers/media/mc/mc-devnode.c b/drivers/media/mc/mc-devnode.c index 5057c48f8870..4ea05e42dafb 100644 --- a/drivers/media/mc/mc-devnode.c +++ b/drivers/media/mc/mc-devnode.c @@ -59,6 +59,10 @@ static void media_devnode_release(struct device *cd) { struct media_devnode *devnode = to_media_devnode(cd); + /* If the devnode has a ref, it is simply released by the user. */ + if (devnode->ref) + return; + if (devnode->minor != -1) media_devnode_free_minor(devnode->minor); @@ -213,6 +217,7 @@ static const struct file_operations media_devnode_fops = { void media_devnode_init(struct media_devnode *devnode) { device_initialize(&devnode->dev); + devnode->dev.release = media_devnode_release; devnode->minor = -1; } @@ -246,7 +251,6 @@ int __must_check media_devnode_register(struct media_devnode *devnode, devnode->dev.bus = &media_bus_type; devnode->dev.devt = MKDEV(MAJOR(media_dev_t), devnode->minor); - devnode->dev.release = media_devnode_release; if (devnode->parent) devnode->dev.parent = devnode->parent; dev_set_name(&devnode->dev, "media%d", devnode->minor); diff --git a/include/media/media-device.h b/include/media/media-device.h index fb0855b217ce..c6816be0eee8 100644 --- a/include/media/media-device.h +++ b/include/media/media-device.h @@ -62,6 +62,7 @@ struct media_entity_notify { * request (and thus the buffer) must be available to the driver. * And once a buffer is queued, then the driver can complete * or delete objects from the request before req_queue exits. + * @release: Release the resources of the media device. */ struct media_device_ops { int (*link_notify)(struct media_link *link, u32 flags, @@ -70,6 +71,7 @@ struct media_device_ops { void (*req_free)(struct media_request *req); int (*req_validate)(struct media_request *req); void (*req_queue)(struct media_request *req); + void (*release)(struct media_device *mdev); }; /** @@ -219,6 +221,30 @@ struct usb_device; */ void media_device_init(struct media_device *mdev); +/** + * media_device_get() - Get a reference to a media device + * + * @mdev: media device + */ +#define media_device_get(mdev) \ + do { \ + dev_dbg((mdev)->dev, "%s: get media device %s\n", \ + __func__, (mdev)->bus_info); \ + get_device(&(mdev)->devnode.dev); \ + } while (0) + +/** + * media_device_put() - Put a reference to a media device + * + * @mdev: media device + */ +#define media_device_put(mdev) \ + do { \ + dev_dbg((mdev)->dev, "%s: put media device %s\n", \ + __func__, (mdev)->bus_info); \ + put_device(&(mdev)->devnode.dev); \ + } while (0) + /** * media_device_cleanup() - Cleanups a media device element * @@ -432,6 +458,8 @@ void __media_device_usb_init(struct media_device *mdev, const char *driver_name); #else +#define media_device_get(mdev) do { } while (0) +#define media_device_put(mdev) do { } while (0) static inline int media_device_register(struct media_device *mdev) { return 0; From patchwork Wed Dec 20 10:37:02 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sakari Ailus X-Patchwork-Id: 756739 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 42A8F21362 for ; Wed, 20 Dec 2023 10:37:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="L0JzkDlx" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1703068650; x=1734604650; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=b8A0zAtDgHgdySNbkiiN2Py2hl+u3/NaWACsnHEcZGk=; b=L0JzkDlxYDTWG51V5sNuCpt0PWFRWLk0/U1ryw4GNdNFRs8xHImS/37f pzCt7fj4Dyxo9Mo1uQHaWS/wUQxMXjBqvMlGzc7cBiCawMzQhDGyNf5Oo hcLjBQKU2Oi3kFQXHnRr3RxlqLYK8P/VCj0Vn8gaOqurrRe5yJshC7QRD XJ2Wxhh9t2CFSfqJXbyLqR0xxWAQhoYbRSf4wIC0meMyXQL6Zv7PnIM/7 oP12RuZnWQmn0CxNzLVG731EM3o5Hdw6ICXNYWdDMfTgAz2pYEm/hXKng SxhozcM/0zx2EbLmrs17E3++Wk5caoHRwdo7wHsrgD38UHGYMEZq6O3Y0 w==; X-IronPort-AV: E=McAfee;i="6600,9927,10929"; a="9174367" X-IronPort-AV: E=Sophos;i="6.04,291,1695711600"; d="scan'208";a="9174367" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2023 02:37:29 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10929"; a="769544269" X-IronPort-AV: E=Sophos;i="6.04,291,1695711600"; d="scan'208";a="769544269" Received: from turnipsi.fi.intel.com (HELO kekkonen.fi.intel.com) ([10.237.72.44]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2023 02:37:28 -0800 Received: from svinhufvud.ger.corp.intel.com (localhost [IPv6:::1]) by kekkonen.fi.intel.com (Postfix) with ESMTP id 8F90F12068E; Wed, 20 Dec 2023 12:37:25 +0200 (EET) From: Sakari Ailus To: linux-media@vger.kernel.org Cc: laurent.pinchart@ideasonboard.com, Hans Verkuil Subject: [PATCH v2 18/29] media: mc: Postpone graph object removal until free Date: Wed, 20 Dec 2023 12:37:02 +0200 Message-Id: <20231220103713.113386-19-sakari.ailus@linux.intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20231220103713.113386-1-sakari.ailus@linux.intel.com> References: <20231220103713.113386-1-sakari.ailus@linux.intel.com> Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The media device itself will be unregistered based on it being unbound and driver's remove callback being called. The graph objects themselves may still be in use; rely on the media device release callback to release them. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil --- drivers/media/mc/mc-device.c | 53 +++++++++++++++++------------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/drivers/media/mc/mc-device.c b/drivers/media/mc/mc-device.c index bbc233e726d2..10426c2796b6 100644 --- a/drivers/media/mc/mc-device.c +++ b/drivers/media/mc/mc-device.c @@ -702,8 +702,33 @@ EXPORT_SYMBOL_GPL(media_device_unregister_entity_notify); static void __media_device_release(struct media_device *mdev) { + struct media_entity *entity; + struct media_entity *next; + struct media_interface *intf, *tmp_intf; + struct media_entity_notify *notify, *nextp; + dev_dbg(mdev->dev, "Media device released\n"); + /* Remove all entities from the media device */ + list_for_each_entry_safe(entity, next, &mdev->entities, graph_obj.list) + __media_device_unregister_entity(entity); + + /* Remove all entity_notify callbacks from the media device */ + list_for_each_entry_safe(notify, nextp, &mdev->entity_notify, list) + __media_device_unregister_entity_notify(mdev, notify); + + /* Remove all interfaces from the media device */ + list_for_each_entry_safe(intf, tmp_intf, &mdev->interfaces, + graph_obj.list) { + /* + * Unlink the interface, but don't free it here; the + * module which created it is responsible for freeing + * it + */ + __media_remove_intf_links(intf); + media_gobj_destroy(&intf->graph_obj); + } + ida_destroy(&mdev->entity_internal_idx); mdev->entity_internal_idx_max = 0; media_graph_walk_cleanup(&mdev->pm_count_walk); @@ -787,42 +812,14 @@ EXPORT_SYMBOL_GPL(__media_device_register); void media_device_unregister(struct media_device *mdev) { - struct media_entity *entity; - struct media_entity *next; - struct media_interface *intf, *tmp_intf; - struct media_entity_notify *notify, *nextp; - if (mdev == NULL) return; mutex_lock(&mdev->graph_mutex); - - /* Check if mdev was ever registered at all */ if (!media_devnode_is_registered(&mdev->devnode)) { mutex_unlock(&mdev->graph_mutex); return; } - - /* Remove all entities from the media device */ - list_for_each_entry_safe(entity, next, &mdev->entities, graph_obj.list) - __media_device_unregister_entity(entity); - - /* Remove all entity_notify callbacks from the media device */ - list_for_each_entry_safe(notify, nextp, &mdev->entity_notify, list) - __media_device_unregister_entity_notify(mdev, notify); - - /* Remove all interfaces from the media device */ - list_for_each_entry_safe(intf, tmp_intf, &mdev->interfaces, - graph_obj.list) { - /* - * Unlink the interface, but don't free it here; the - * module which created it is responsible for freeing - * it - */ - __media_remove_intf_links(intf); - media_gobj_destroy(&intf->graph_obj); - } - mutex_unlock(&mdev->graph_mutex); device_remove_file(&mdev->devnode.dev, &dev_attr_model); From patchwork Wed Dec 20 10:37:04 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sakari Ailus X-Patchwork-Id: 756738 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DFF6421378 for ; Wed, 20 Dec 2023 10:37:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="GdMT92t3" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1703068651; x=1734604651; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=OJv0/BwKZ5DTc28TXBnAuE0FG/a2mjeyCr2XuQmfLVc=; b=GdMT92t3iZrIo8tuEyn6vOReTPELO2nJ2A2j91IxfAXps3DLY26qowwu 8m9jKKqMrLAFd5hwGTDtS/NBU8hK8B5nWcdmWr0be2+NybOV+1Uk/e7BP xX1nb/PxYqS3oxzRfN13Si1jqDPK39PTMu4Mmfl/VydUN+OBp1X0gGEfU fajmqVUQkgZaWc0t9qAm31dRrA6wuJ2zyvicLj7Zp7jsCt+W+lGMF77Ki ao85azttM5SeDg4b1JJCu3hapPmqZjio7t2vnPGV7sNW9dcu4skRWVx5m 2HuAHap8BDSc0i+LRHoTO2TcmrJZ0gYgVGNM+/p3aijE7wIewuHuih8e7 Q==; X-IronPort-AV: E=McAfee;i="6600,9927,10929"; a="9174377" X-IronPort-AV: E=Sophos;i="6.04,291,1695711600"; d="scan'208";a="9174377" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2023 02:37:31 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10929"; a="769544271" X-IronPort-AV: E=Sophos;i="6.04,291,1695711600"; d="scan'208";a="769544271" Received: from turnipsi.fi.intel.com (HELO kekkonen.fi.intel.com) ([10.237.72.44]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2023 02:37:29 -0800 Received: from svinhufvud.ger.corp.intel.com (localhost [IPv6:::1]) by kekkonen.fi.intel.com (Postfix) with ESMTP id BB6B7120788; Wed, 20 Dec 2023 12:37:26 +0200 (EET) From: Sakari Ailus To: linux-media@vger.kernel.org Cc: laurent.pinchart@ideasonboard.com, Hans Verkuil Subject: [PATCH v2 20/29] media: ipu3-cio2: Call v4l2_device_unregister() earlier Date: Wed, 20 Dec 2023 12:37:04 +0200 Message-Id: <20231220103713.113386-21-sakari.ailus@linux.intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20231220103713.113386-1-sakari.ailus@linux.intel.com> References: <20231220103713.113386-1-sakari.ailus@linux.intel.com> Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 v4l2_device_unregister() unregisters V4L2 sub-device nodes among other things. Call it before releasing memory and other resources. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil --- drivers/media/pci/intel/ipu3/ipu3-cio2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index 5d3b0ffd3d08..da82d09b46ab 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -1827,11 +1827,11 @@ static void cio2_pci_remove(struct pci_dev *pci_dev) struct cio2_device *cio2 = pci_get_drvdata(pci_dev); media_device_unregister(&cio2->media_dev); + v4l2_device_unregister(&cio2->v4l2_dev); v4l2_async_nf_unregister(&cio2->notifier); v4l2_async_nf_cleanup(&cio2->notifier); cio2_queues_exit(cio2); cio2_fbpt_exit_dummy(cio2); - v4l2_device_unregister(&cio2->v4l2_dev); media_device_cleanup(&cio2->media_dev); mutex_destroy(&cio2->lock); From patchwork Wed Dec 20 10:37:06 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sakari Ailus X-Patchwork-Id: 756737 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D8F7A219EF for ; Wed, 20 Dec 2023 10:37:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="WyZB2tKK" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1703068652; x=1734604652; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=+M6yyO46Xtu1fwW0RMGaWr7x2lDqmtvQjpWHYItP3FY=; b=WyZB2tKK2PgenDKA3m8OkGxgmjLADSYDo4v9d9qspK7WVoqwvKtSobAt YSqReeBRCdE+Lw0jNsJH3CY2yqx8Qb3JbyHH8jZV5FjWgWkj3ZZOZ/81u VqV2Yj49daa8a/XjEP6wf+AjtiqkGEd7owewXr0HzMJ9PVb15SJ5/7caF gCpuBAQkCUhz+MhsRqN8XmmeuRUrEXjX1fIS8V9QDgjpMvY4YK2uZ5De8 75YD+oZwGrFteu6dQ1GRdWosQBK+Lc5SYvn18wBFZuE980waZrZ1JaseX RadqELlB9bIQ6a19sxVXVW+e9esMwWZI4ywfqAbItO8nDVSxvEX8fe1zk A==; X-IronPort-AV: E=McAfee;i="6600,9927,10929"; a="9174387" X-IronPort-AV: E=Sophos;i="6.04,291,1695711600"; d="scan'208";a="9174387" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2023 02:37:31 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10929"; a="769544273" X-IronPort-AV: E=Sophos;i="6.04,291,1695711600"; d="scan'208";a="769544273" Received: from turnipsi.fi.intel.com (HELO kekkonen.fi.intel.com) ([10.237.72.44]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2023 02:37:30 -0800 Received: from svinhufvud.ger.corp.intel.com (localhost [IPv6:::1]) by kekkonen.fi.intel.com (Postfix) with ESMTP id DB5E9120A70; Wed, 20 Dec 2023 12:37:27 +0200 (EET) From: Sakari Ailus To: linux-media@vger.kernel.org Cc: laurent.pinchart@ideasonboard.com, Hans Verkuil Subject: [PATCH v2 22/29] media: ipu3-cio2: Release the cio2 device context by media device callback Date: Wed, 20 Dec 2023 12:37:06 +0200 Message-Id: <20231220103713.113386-23-sakari.ailus@linux.intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20231220103713.113386-1-sakari.ailus@linux.intel.com> References: <20231220103713.113386-1-sakari.ailus@linux.intel.com> Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Use the media device release callback to release the cio2 device's data structure. This approach has the benefit of not releasing memory which may still be accessed through open file handles whilst the ipu3-cio2 driver is being unbound. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil --- drivers/media/pci/intel/ipu3/ipu3-cio2.c | 58 ++++++++++++++++-------- 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index 3222ec5b8345..bff66e6d3b1e 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -238,9 +238,15 @@ static int cio2_fbpt_init(struct cio2_device *cio2, struct cio2_queue *q) return 0; } -static void cio2_fbpt_exit(struct cio2_queue *q, struct device *dev) +static int cio2_fbpt_exit(struct cio2_queue *q, struct device *dev) { + if (!q->fbpt) + return -ENOENT; + dma_free_coherent(dev, CIO2_FBPT_SIZE, q->fbpt, q->fbpt_bus_addr); + q->fbpt = NULL; + + return 0; } /**************** CSI2 hardware setup ****************/ @@ -1643,13 +1649,13 @@ static int cio2_queue_init(struct cio2_device *cio2, struct cio2_queue *q) static void cio2_queue_exit(struct cio2_device *cio2, struct cio2_queue *q) { - vb2_video_unregister_device(&q->vdev); media_entity_cleanup(&q->vdev.entity); v4l2_device_unregister_subdev(&q->subdev); media_entity_cleanup(&q->subdev.entity); - cio2_fbpt_exit(q, &cio2->pci_dev->dev); - mutex_destroy(&q->subdev_lock); - mutex_destroy(&q->lock); + if (!cio2_fbpt_exit(q, &cio2->pci_dev->dev)) { + mutex_destroy(&q->subdev_lock); + mutex_destroy(&q->lock); + } } static int cio2_queues_init(struct cio2_device *cio2) @@ -1695,6 +1701,23 @@ static int cio2_check_fwnode_graph(struct fwnode_handle *fwnode) return cio2_check_fwnode_graph(fwnode->secondary); } +static void cio2_media_release(struct media_device *mdev) +{ + struct cio2_device *cio2 = + container_of(mdev, struct cio2_device, media_dev); + + v4l2_async_nf_cleanup(&cio2->notifier); + cio2_queues_exit(cio2); + cio2_fbpt_exit_dummy(cio2); + mutex_destroy(&cio2->lock); + + kfree(cio2); +} + +static const struct media_device_ops cio2_mdev_ops = { + .release = cio2_media_release, +}; + /**************** PCI interface ****************/ static int cio2_pci_probe(struct pci_dev *pci_dev, @@ -1722,7 +1745,7 @@ static int cio2_pci_probe(struct pci_dev *pci_dev, return r; } - cio2 = devm_kzalloc(dev, sizeof(*cio2), GFP_KERNEL); + cio2 = kzalloc(sizeof(*cio2), GFP_KERNEL); if (!cio2) return -ENOMEM; cio2->pci_dev = pci_dev; @@ -1767,6 +1790,7 @@ static int cio2_pci_probe(struct pci_dev *pci_dev, mutex_init(&cio2->lock); cio2->media_dev.dev = dev; + cio2->media_dev.ops = &cio2_mdev_ops; strscpy(cio2->media_dev.model, CIO2_DEVICE_NAME, sizeof(cio2->media_dev.model)); cio2->media_dev.hw_revision = 0; @@ -1774,7 +1798,7 @@ static int cio2_pci_probe(struct pci_dev *pci_dev, media_device_init(&cio2->media_dev); r = media_device_register(&cio2->media_dev); if (r < 0) - goto fail_mutex_destroy; + goto fail_media_device_put; cio2->v4l2_dev.mdev = &cio2->media_dev; r = v4l2_device_register(dev, &cio2->v4l2_dev); @@ -1808,35 +1832,33 @@ static int cio2_pci_probe(struct pci_dev *pci_dev, fail_clean_notifier: v4l2_async_nf_unregister(&cio2->notifier); - v4l2_async_nf_cleanup(&cio2->notifier); - cio2_queues_exit(cio2); + fail_v4l2_device_unregister: v4l2_device_unregister(&cio2->v4l2_dev); + fail_media_device_unregister: media_device_unregister(&cio2->media_dev); - media_device_cleanup(&cio2->media_dev); -fail_mutex_destroy: - mutex_destroy(&cio2->lock); - cio2_fbpt_exit_dummy(cio2); +fail_media_device_put: + media_device_put(&cio2->media_dev); return r; } static void cio2_pci_remove(struct pci_dev *pci_dev) { struct cio2_device *cio2 = pci_get_drvdata(pci_dev); + unsigned int i; media_device_unregister(&cio2->media_dev); + for (i = 0; i < CIO2_QUEUES; i++) + vb2_video_unregister_device(&cio2->queue[i].vdev); v4l2_device_unregister(&cio2->v4l2_dev); v4l2_async_nf_unregister(&cio2->notifier); - v4l2_async_nf_cleanup(&cio2->notifier); - cio2_queues_exit(cio2); - cio2_fbpt_exit_dummy(cio2); - media_device_cleanup(&cio2->media_dev); - mutex_destroy(&cio2->lock); pm_runtime_forbid(&pci_dev->dev); pm_runtime_get_noresume(&pci_dev->dev); + + media_device_put(&cio2->media_dev); } static int __maybe_unused cio2_runtime_suspend(struct device *dev) From patchwork Wed Dec 20 10:37:08 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sakari Ailus X-Patchwork-Id: 756736 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B27DA22060 for ; Wed, 20 Dec 2023 10:37:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="ljVEerAw" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1703068654; x=1734604654; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=sRLZ1emkDYhb5x7smdmo1s2AjGA9Ic8j2ytBQpH0Jv4=; b=ljVEerAw9F3ZPadg8W14gGD3GW1o/XnwZr7SJdiSlfEoFJKw4xdI0qYx l6R0ARb8Av2S+QCwG3jeN3EjQeDE2CRuFt5aJU8yFSfPM0kpwHsJe4B1r 2oO91hlWNkFpxvVfsj98xY3LCCbk/XtmipuPz1AtbT6kLbOg3E+wrWx/u xRc3e81/c1Pwv+GOzbZCQEqwdX6/pWQN0Y9pARYBXKCGf+YzK7ctKWcPU qLOzsaaVkRdB8wP8rOidi0geqg8xT7iiInvt9rfE04y9OeFeCD/GunGrp xzbrjDnGrnYNiUPOXTclEN39Ly58DfAYzkWDdtuUs1wHBSwwKvP1ozkc2 w==; X-IronPort-AV: E=McAfee;i="6600,9927,10929"; a="9174398" X-IronPort-AV: E=Sophos;i="6.04,291,1695711600"; d="scan'208";a="9174398" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2023 02:37:33 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10929"; a="769544275" X-IronPort-AV: E=Sophos;i="6.04,291,1695711600"; d="scan'208";a="769544275" Received: from turnipsi.fi.intel.com (HELO kekkonen.fi.intel.com) ([10.237.72.44]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2023 02:37:32 -0800 Received: from svinhufvud.ger.corp.intel.com (localhost [IPv6:::1]) by kekkonen.fi.intel.com (Postfix) with ESMTP id 3C1241201D0; Wed, 20 Dec 2023 12:37:29 +0200 (EET) From: Sakari Ailus To: linux-media@vger.kernel.org Cc: laurent.pinchart@ideasonboard.com, Hans Verkuil Subject: [PATCH v2 24/29] media: Documentation: Document how Media device resources are released Date: Wed, 20 Dec 2023 12:37:08 +0200 Message-Id: <20231220103713.113386-25-sakari.ailus@linux.intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20231220103713.113386-1-sakari.ailus@linux.intel.com> References: <20231220103713.113386-1-sakari.ailus@linux.intel.com> Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Document that after unregistering, Media device memory resources are released by the release() callback rather than by calling media_device_cleanup(). Also add that driver memory resources should be bound to the Media device, not V4L2 device. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil --- Documentation/driver-api/media/mc-core.rst | 18 ++++++++++++++++-- include/media/media-device.h | 6 ++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/Documentation/driver-api/media/mc-core.rst b/Documentation/driver-api/media/mc-core.rst index 2456950ce8ff..346f67760671 100644 --- a/Documentation/driver-api/media/mc-core.rst +++ b/Documentation/driver-api/media/mc-core.rst @@ -46,13 +46,27 @@ Drivers initialise media device instances by calling :c:func:`media_device_init()`. After initialising a media device instance, it is registered by calling :c:func:`__media_device_register()` via the macro ``media_device_register()`` and unregistered by calling -:c:func:`media_device_unregister()`. An initialised media device must be -eventually cleaned up by calling :c:func:`media_device_cleanup()`. +:c:func:`media_device_unregister()`. The resources of an unregistered media +device will be released by the ``release()`` callback of :c:type:`media_device` +ops, which will be called when the last user of the media device has released it +calling :c:func:`media_device_put()`. + +The ``release()`` callback is the way all the resources of the media device are +released once :c:func:`media_device_init()` has been called. This is also +relevant during device driver's probe function as the ``release()`` callback +will also have to be able to safely release the resources related to a partially +initialised media device. Note that it is not allowed to unregister a media device instance that was not previously registered, or clean up a media device instance that was not previously initialised. +Media device and driver's per-device context +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Drivers should use the struct media_device_ops ``release()`` callback to release +their own resources and not e.g. that of the struct v4l2_device. + Entities ^^^^^^^^ diff --git a/include/media/media-device.h b/include/media/media-device.h index c6816be0eee8..98e1892f1b51 100644 --- a/include/media/media-device.h +++ b/include/media/media-device.h @@ -250,8 +250,10 @@ void media_device_init(struct media_device *mdev); * * @mdev: pointer to struct &media_device * - * This function that will destroy the graph_mutex that is - * initialized in media_device_init(). + * This function that will destroy the graph_mutex that is initialized in + * media_device_init(). Note that *only* drivers that do not manage releasing + * the memory of th media device itself call this function. This function is + * thus effectively DEPRECATED. */ void media_device_cleanup(struct media_device *mdev); From patchwork Wed Dec 20 10:37:10 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sakari Ailus X-Patchwork-Id: 756735 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9E6F2208C9 for ; Wed, 20 Dec 2023 10:37:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="ZPs1opUt" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1703068655; x=1734604655; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=na+12loNNkFs8gMbbIPJRpDsi4oBG8NL0QQSFhxlflY=; b=ZPs1opUtbqi7YdQ9QR/4oFFGfciBK9JQcnVtNKBXhPhkD7B90jq8zxHu 6pPaTTHgO1ArESP9L5r44CRMYevKrjSW0WtLzlvmi4hlQrFeZginyREp2 /ELvcqQG4Nd9YOpPQSZLUSOTIsdmbelRKDy0BMq9r+UMuOohNT2xpAga6 fn/r/xH3AGzfAP6AP5GHS2stLhfAYybud4AO2haAAKDpIrRJGW2GG4jwq dfkYgwcS0iAM29w89bmh/loPI0GqBei3bY7Zq5JNbD1wHm3LKpeRhPcfM XFtWQ0Gfw7aPni4H0uxAsSaO0AL2rfq168MkSdGHXtjoq49Q5niOgGs/+ Q==; X-IronPort-AV: E=McAfee;i="6600,9927,10929"; a="9174408" X-IronPort-AV: E=Sophos;i="6.04,291,1695711600"; d="scan'208";a="9174408" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2023 02:37:34 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10929"; a="769544278" X-IronPort-AV: E=Sophos;i="6.04,291,1695711600"; d="scan'208";a="769544278" Received: from turnipsi.fi.intel.com (HELO kekkonen.fi.intel.com) ([10.237.72.44]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2023 02:37:33 -0800 Received: from svinhufvud.ger.corp.intel.com (localhost [IPv6:::1]) by kekkonen.fi.intel.com (Postfix) with ESMTP id 9721B120706; Wed, 20 Dec 2023 12:37:30 +0200 (EET) From: Sakari Ailus To: linux-media@vger.kernel.org Cc: laurent.pinchart@ideasonboard.com, Hans Verkuil Subject: [PATCH v2 26/29] media: mc: Maintain a list of open file handles in a media device Date: Wed, 20 Dec 2023 12:37:10 +0200 Message-Id: <20231220103713.113386-27-sakari.ailus@linux.intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20231220103713.113386-1-sakari.ailus@linux.intel.com> References: <20231220103713.113386-1-sakari.ailus@linux.intel.com> Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The list of file handles is needed to deliver media events as well as for other purposes in the future. Signed-off-by: Sakari Ailus --- drivers/media/mc/mc-device.c | 23 ++++++++++++++++++++++- drivers/media/mc/mc-devnode.c | 2 +- include/media/media-devnode.h | 4 +++- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/drivers/media/mc/mc-device.c b/drivers/media/mc/mc-device.c index 67a39cb63f89..9cc055deeec9 100644 --- a/drivers/media/mc/mc-device.c +++ b/drivers/media/mc/mc-device.c @@ -45,9 +45,11 @@ static inline void __user *media_get_uptr(__u64 arg) return (void __user *)(uintptr_t)arg; } -static int media_device_open(struct file *filp) +static int media_device_open(struct media_devnode *devnode, struct file *filp) { + struct media_device *mdev = to_media_device(devnode); struct media_device_fh *fh; + unsigned long flags; fh = kzalloc(sizeof(*fh), GFP_KERNEL); if (!fh) @@ -55,12 +57,23 @@ static int media_device_open(struct file *filp) filp->private_data = &fh->fh; + spin_lock_irqsave(&mdev->fh_list_lock, flags); + list_add(&fh->mdev_list, &mdev->fh_list); + spin_unlock_irqrestore(&mdev->fh_list_lock, flags); + return 0; } static int media_device_close(struct file *filp) { + struct media_devnode *devnode = media_devnode_data(filp); + struct media_device *mdev = to_media_device(devnode); struct media_device_fh *fh = media_device_fh(filp); + unsigned long flags; + + spin_lock_irqsave(&mdev->fh_list_lock, flags); + list_del(&fh->mdev_list); + spin_unlock_irqrestore(&mdev->fh_list_lock, flags); kfree(fh); @@ -769,11 +782,13 @@ void media_device_init(struct media_device *mdev) INIT_LIST_HEAD(&mdev->pads); INIT_LIST_HEAD(&mdev->links); INIT_LIST_HEAD(&mdev->entity_notify); + INIT_LIST_HEAD(&mdev->fh_list); mutex_init(&mdev->req_queue_mutex); mutex_init(&mdev->graph_mutex); ida_init(&mdev->entity_internal_idx); atomic_set(&mdev->request_id, 0); + spin_lock_init(&mdev->fh_list_lock); mdev->devnode.release = media_device_release; media_devnode_init(&mdev->devnode); @@ -824,6 +839,8 @@ EXPORT_SYMBOL_GPL(__media_device_register); void media_device_unregister(struct media_device *mdev) { + unsigned long flags; + if (mdev == NULL) return; @@ -834,6 +851,10 @@ void media_device_unregister(struct media_device *mdev) } mutex_unlock(&mdev->graph_mutex); + spin_lock_irqsave(&mdev->fh_list_lock, flags); + list_del_init(&mdev->fh_list); + spin_unlock_irqrestore(&mdev->fh_list_lock, flags); + device_remove_file(&mdev->devnode.dev, &dev_attr_model); dev_dbg(mdev->dev, "Media device unregistering\n"); media_devnode_unregister(&mdev->devnode); diff --git a/drivers/media/mc/mc-devnode.c b/drivers/media/mc/mc-devnode.c index 04d376015526..0b5c24828e24 100644 --- a/drivers/media/mc/mc-devnode.c +++ b/drivers/media/mc/mc-devnode.c @@ -171,7 +171,7 @@ static int media_open(struct inode *inode, struct file *filp) get_device(&devnode->dev); mutex_unlock(&media_devnode_lock); - ret = devnode->fops->open(filp); + ret = devnode->fops->open(devnode, filp); if (ret) { put_device(&devnode->dev); return ret; diff --git a/include/media/media-devnode.h b/include/media/media-devnode.h index b0efdde4ffd8..840f7ae852d3 100644 --- a/include/media/media-devnode.h +++ b/include/media/media-devnode.h @@ -21,6 +21,8 @@ #include #include +struct media_devnode; + /* * Flag to mark the media_devnode struct as registered. Drivers must not touch * this flag directly, it will be set and cleared by media_devnode_register and @@ -49,7 +51,7 @@ struct media_file_operations { __poll_t (*poll) (struct file *, struct poll_table_struct *); long (*ioctl) (struct file *, unsigned int, unsigned long); long (*compat_ioctl) (struct file *, unsigned int, unsigned long); - int (*open) (struct file *); + int (*open) (struct media_devnode *, struct file *); int (*release) (struct file *); }; From patchwork Wed Dec 20 10:37:11 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sakari Ailus X-Patchwork-Id: 756734 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C4BC722060 for ; Wed, 20 Dec 2023 10:37:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="Yn0VU+th" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1703068656; x=1734604656; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=nPi3JMGp0gtSZuI8E+B44cm0m6EVcZxK+vx4DPFzbts=; b=Yn0VU+thi3Ujm05tQtezKYK1+dTTiplatCTfPpaiOnwPcwvsCHRy24px LRo/xmea/dLiuAeGSOObPykXwVrpVQpKf+RunUlnH/0zzrguBIv3PExOV LLcGFd3OyAvHAt+BTx+Dbx36sr/VlDjMAyWvx8/+vjxjPOn0pTl+sJ8Sg jKjnHJtR3VvAO1UxnEeVaR9HoMugEh04QD3zEkNuakzVK0quJcTf0U5ND ZByrQvPXzGNtDEKq2/VSfLS1rhQBxwKx3KOqhs5/453jMtYWZt8InYmZ7 gYJ/UezLcqDHo9DVtmFTeoytV1hCjVM5brlmcmPL2p7qY8aFWC6cVuYK3 g==; X-IronPort-AV: E=McAfee;i="6600,9927,10929"; a="9174412" X-IronPort-AV: E=Sophos;i="6.04,291,1695711600"; d="scan'208";a="9174412" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2023 02:37:35 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10929"; a="769544280" X-IronPort-AV: E=Sophos;i="6.04,291,1695711600"; d="scan'208";a="769544280" Received: from turnipsi.fi.intel.com (HELO kekkonen.fi.intel.com) ([10.237.72.44]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Dec 2023 02:37:33 -0800 Received: from svinhufvud.ger.corp.intel.com (localhost [IPv6:::1]) by kekkonen.fi.intel.com (Postfix) with ESMTP id 2E862120788; Wed, 20 Dec 2023 12:37:31 +0200 (EET) From: Sakari Ailus To: linux-media@vger.kernel.org Cc: laurent.pinchart@ideasonboard.com, Hans Verkuil Subject: [PATCH v2 27/29] media: mc: Implement best effort media device removal safety sans refcount Date: Wed, 20 Dec 2023 12:37:11 +0200 Message-Id: <20231220103713.113386-28-sakari.ailus@linux.intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20231220103713.113386-1-sakari.ailus@linux.intel.com> References: <20231220103713.113386-1-sakari.ailus@linux.intel.com> Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Add a new helper data structures media_devnode_compat_ref and media_devnode_cdev. The latter is used to prevent user space from calling IOCTLs or other system calls to the media device that has been already unregistered and the former to help with obtaining the container struct (either media_devnode_compat_ref or media_devnode) in media_open(). The media device's memory may of course still be released during the call but there is only so much that can be done to this without the driver managing the lifetime of the resources it needs somehow. This patch should be reverted once all drivers have been converted to manage their resources' lifetime. Signed-off-by: Sakari Ailus --- drivers/media/mc/mc-device.c | 55 ++++++++++---- drivers/media/mc/mc-devnode.c | 117 ++++++++++++++++++++++------- drivers/media/v4l2-core/v4l2-dev.c | 28 +++++-- include/media/media-devnode.h | 64 +++++++++++++++- 4 files changed, 210 insertions(+), 54 deletions(-) diff --git a/drivers/media/mc/mc-device.c b/drivers/media/mc/mc-device.c index 9cc055deeec9..97d63146b344 100644 --- a/drivers/media/mc/mc-device.c +++ b/drivers/media/mc/mc-device.c @@ -55,6 +55,8 @@ static int media_device_open(struct media_devnode *devnode, struct file *filp) if (!fh) return -ENOMEM; + fh->fh.ref = devnode->ref; + filp->private_data = &fh->fh; spin_lock_irqsave(&mdev->fh_list_lock, flags); @@ -66,14 +68,19 @@ static int media_device_open(struct media_devnode *devnode, struct file *filp) static int media_device_close(struct file *filp) { - struct media_devnode *devnode = media_devnode_data(filp); - struct media_device *mdev = to_media_device(devnode); - struct media_device_fh *fh = media_device_fh(filp); - unsigned long flags; + struct media_device_fh *fh; - spin_lock_irqsave(&mdev->fh_list_lock, flags); - list_del(&fh->mdev_list); - spin_unlock_irqrestore(&mdev->fh_list_lock, flags); + fh = media_device_fh(filp); + + if (!fh->fh.ref || atomic_read(&fh->fh.ref->registered)) { + struct media_devnode *devnode = media_devnode_data(filp); + struct media_device *mdev = to_media_device(devnode); + unsigned long flags; + + spin_lock_irqsave(&mdev->fh_list_lock, flags); + list_del(&fh->mdev_list); + spin_unlock_irqrestore(&mdev->fh_list_lock, flags); + } kfree(fh); @@ -812,28 +819,45 @@ EXPORT_SYMBOL_GPL(media_device_cleanup); int __must_check __media_device_register(struct media_device *mdev, struct module *owner) { + struct media_devnode_compat_ref *ref = NULL; int ret; + if (!mdev->ops || !mdev->ops->release) { + ref = kzalloc(sizeof(*mdev->devnode.ref), GFP_KERNEL); + if (!ref) + return -ENOMEM; + } + /* Register the device node. */ mdev->devnode.fops = &media_device_fops; mdev->devnode.parent = mdev->dev; + mdev->devnode.ref = ref; /* Set version 0 to indicate user-space that the graph is static */ mdev->topology_version = 0; ret = media_devnode_register(&mdev->devnode, owner); if (ret < 0) - return ret; + goto out_put_ref; + + ret = device_create_file(media_devnode_dev(&mdev->devnode), + &dev_attr_model); + if (ret < 0) + goto out_devnode_unregister; - ret = device_create_file(&mdev->devnode.dev, &dev_attr_model); - if (ret < 0) { - media_devnode_unregister(&mdev->devnode); - return ret; - } dev_dbg(mdev->dev, "Media device registered\n"); return 0; + +out_devnode_unregister: + media_devnode_unregister(&mdev->devnode); + +out_put_ref: + if (ref) + put_device(&ref->dev); + + return ret; } EXPORT_SYMBOL_GPL(__media_device_register); @@ -855,9 +879,12 @@ void media_device_unregister(struct media_device *mdev) list_del_init(&mdev->fh_list); spin_unlock_irqrestore(&mdev->fh_list_lock, flags); - device_remove_file(&mdev->devnode.dev, &dev_attr_model); + device_remove_file(media_devnode_dev(&mdev->devnode), &dev_attr_model); dev_dbg(mdev->dev, "Media device unregistering\n"); media_devnode_unregister(&mdev->devnode); + + if (mdev->devnode.ref) + put_device(&mdev->devnode.ref->dev); } EXPORT_SYMBOL_GPL(media_device_unregister); diff --git a/drivers/media/mc/mc-devnode.c b/drivers/media/mc/mc-devnode.c index 0b5c24828e24..d64bb501a3ee 100644 --- a/drivers/media/mc/mc-devnode.c +++ b/drivers/media/mc/mc-devnode.c @@ -71,19 +71,45 @@ static void media_devnode_release(struct device *cd) devnode->release(devnode); } +static void media_devnode_ref_release(struct device *cd) +{ + struct media_devnode_compat_ref *ref = + container_of_const(cd, struct media_devnode_compat_ref, dev); + + media_devnode_free_minor(ref->minor); + + kfree(ref); +} + +struct media_devnode *to_media_devnode(struct device *dev) +{ + if (dev->release == media_devnode_release) + return container_of(dev, struct media_devnode, dev); + + return container_of(dev, struct media_devnode_compat_ref, dev)->devnode; +} + static struct bus_type media_bus_type = { .name = MEDIA_NAME, }; +static bool media_devnode_is_registered_compat(struct media_devnode_fh *fh) +{ + if (fh->ref) + return atomic_read(&fh->ref->registered); + + return media_devnode_is_registered(fh->devnode); +} + static ssize_t media_read(struct file *filp, char __user *buf, size_t sz, loff_t *off) { struct media_devnode *devnode = media_devnode_data(filp); + if (!media_devnode_is_registered_compat(filp->private_data)) + return -EIO; if (!devnode->fops->read) return -EINVAL; - if (!media_devnode_is_registered(devnode)) - return -EIO; return devnode->fops->read(filp, buf, sz, off); } @@ -92,10 +118,10 @@ static ssize_t media_write(struct file *filp, const char __user *buf, { struct media_devnode *devnode = media_devnode_data(filp); + if (!media_devnode_is_registered_compat(filp->private_data)) + return -EIO; if (!devnode->fops->write) return -EINVAL; - if (!media_devnode_is_registered(devnode)) - return -EIO; return devnode->fops->write(filp, buf, sz, off); } @@ -104,7 +130,7 @@ static __poll_t media_poll(struct file *filp, { struct media_devnode *devnode = media_devnode_data(filp); - if (!media_devnode_is_registered(devnode)) + if (!media_devnode_is_registered_compat(filp->private_data)) return EPOLLERR | EPOLLHUP; if (!devnode->fops->poll) return DEFAULT_POLLMASK; @@ -116,14 +142,9 @@ __media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg, long (*ioctl_func)(struct file *filp, unsigned int cmd, unsigned long arg)) { - struct media_devnode *devnode = media_devnode_data(filp); - if (!ioctl_func) return -ENOTTY; - if (!media_devnode_is_registered(devnode)) - return -EIO; - return ioctl_func(filp, cmd, arg); } @@ -131,6 +152,9 @@ static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct media_devnode *devnode = media_devnode_data(filp); + if (!media_devnode_is_registered_compat(filp->private_data)) + return -EIO; + return __media_ioctl(filp, cmd, arg, devnode->fops->ioctl); } @@ -141,6 +165,9 @@ static long media_compat_ioctl(struct file *filp, unsigned int cmd, { struct media_devnode *devnode = media_devnode_data(filp); + if (!media_devnode_is_registered_compat(filp->private_data)) + return -EIO; + return __media_ioctl(filp, cmd, arg, devnode->fops->compat_ioctl); } @@ -149,6 +176,7 @@ static long media_compat_ioctl(struct file *filp, unsigned int cmd, /* Override for the open function */ static int media_open(struct inode *inode, struct file *filp) { + struct media_devnode_cdev *mcdev; struct media_devnode *devnode; struct media_devnode_fh *fh; int ret; @@ -160,7 +188,12 @@ static int media_open(struct inode *inode, struct file *filp) * a crash. */ mutex_lock(&media_devnode_lock); - devnode = container_of(inode->i_cdev, struct media_devnode, cdev); + mcdev = container_of(inode->i_cdev, struct media_devnode_cdev, cdev); + if (mcdev->is_compat_ref) + devnode = container_of(mcdev, struct media_devnode_compat_ref, + mcdev)->devnode; + else + devnode = container_of(mcdev, struct media_devnode, mcdev); /* return ENXIO if the media device has been removed already or if it is not registered anymore. */ if (!media_devnode_is_registered(devnode)) { @@ -168,12 +201,12 @@ static int media_open(struct inode *inode, struct file *filp) return -ENXIO; } /* and increase the device refcount */ - get_device(&devnode->dev); + get_device(media_devnode_dev(devnode)); mutex_unlock(&media_devnode_lock); ret = devnode->fops->open(devnode, filp); if (ret) { - put_device(&devnode->dev); + put_device(media_devnode_dev(devnode)); return ret; } @@ -186,15 +219,21 @@ static int media_open(struct inode *inode, struct file *filp) /* Override for the release function */ static int media_release(struct inode *inode, struct file *filp) { - struct media_devnode *devnode = media_devnode_data(filp); - - devnode->fops->release(filp); + struct media_devnode_fh *fh = filp->private_data; + struct device *dev; + + if (!fh->ref) { + dev = &fh->devnode->dev; + fh->devnode->fops->release(filp); + } else { + dev = &fh->ref->dev; + fh->ref->release(filp); + } filp->private_data = NULL; - /* decrease the refcount unconditionally since the release() - return value is ignored. */ - put_device(&devnode->dev); + put_device(dev); + return 0; } @@ -222,6 +261,9 @@ void media_devnode_init(struct media_devnode *devnode) int __must_check media_devnode_register(struct media_devnode *devnode, struct module *owner) { + struct media_devnode_compat_ref *ref = devnode->ref; + struct cdev *cdev; + struct device *dev; int minor; int ret; @@ -243,18 +285,31 @@ int __must_check media_devnode_register(struct media_devnode *devnode, devnode->minor = minor; /* Part 2: Initialize the media and character devices */ - cdev_init(&devnode->cdev, &media_devnode_fops); - devnode->cdev.owner = owner; - kobject_set_name(&devnode->cdev.kobj, "media%d", devnode->minor); - - devnode->dev.bus = &media_bus_type; - devnode->dev.devt = MKDEV(MAJOR(media_dev_t), devnode->minor); + cdev = ref ? &ref->mcdev.cdev : &devnode->mcdev.cdev; + cdev_init(cdev, &media_devnode_fops); + cdev->owner = owner; + kobject_set_name(&cdev->kobj, "media%d", devnode->minor); + + if (!ref) { + dev = &devnode->dev; + } else { + ref->mcdev.is_compat_ref = true; + device_initialize(&ref->dev); + atomic_set(&ref->registered, 1); + ref->devnode = devnode; + ref->minor = devnode->minor; + ref->release = devnode->fops->release; + dev = &ref->dev; + dev->release = media_devnode_ref_release; + } + dev->bus = &media_bus_type; + dev->devt = MKDEV(MAJOR(media_dev_t), devnode->minor); if (devnode->parent) - devnode->dev.parent = devnode->parent; - dev_set_name(&devnode->dev, "media%d", devnode->minor); + dev->parent = devnode->parent; + dev_set_name(dev, "media%d", devnode->minor); /* Part 3: Add the media and character devices */ - ret = cdev_device_add(&devnode->cdev, &devnode->dev); + ret = cdev_device_add(cdev, dev); if (ret < 0) { pr_err("%s: cdev_device_add failed\n", __func__); goto cdev_add_error; @@ -279,11 +334,15 @@ void media_devnode_unregister(struct media_devnode *devnode) if (!media_devnode_is_registered(devnode)) return; + if (devnode->ref) + atomic_set(&devnode->ref->registered, 0); + mutex_lock(&media_devnode_lock); clear_bit(MEDIA_FLAG_REGISTERED, &devnode->flags); mutex_unlock(&media_devnode_lock); - cdev_device_del(&devnode->cdev, &devnode->dev); + cdev_device_del(devnode->ref ? &devnode->ref->mcdev.cdev : + &devnode->mcdev.cdev, media_devnode_dev(devnode)); } /* diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index c1e4995eaf5c..e18e7199ed83 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -179,7 +179,7 @@ static void v4l2_device_release(struct device *cd) bool v4l2_dev_has_release = v4l2_dev->release; #ifdef CONFIG_MEDIA_CONTROLLER struct media_device *mdev = v4l2_dev->mdev; - bool mdev_has_release = mdev && mdev->ops && mdev->ops->release; + bool mdev_has_ref = mdev && mdev->devnode.ref; #endif mutex_lock(&videodev_lock); @@ -212,12 +212,24 @@ static void v4l2_device_release(struct device *cd) } #endif - /* Release video_device and perform other - cleanups as needed. */ + /* + * Put struct media_devnode_compat_ref here as indicated by + * mdev_has_ref. mdev may be released by vdev->release() below. + */ +#ifdef CONFIG_MEDIA_CONTROLLER + if (mdev && mdev_has_ref) + media_device_put(mdev); +#endif + + /* Release video_device and perform other cleanups as needed. */ vdev->release(vdev); #ifdef CONFIG_MEDIA_CONTROLLER - if (mdev) + /* + * Put a reference to struct media_device acquired in + * video_register_media_controller(). + */ + if (mdev && !mdev_has_ref) media_device_put(mdev); /* @@ -225,16 +237,18 @@ static void v4l2_device_release(struct device *cd) * embedded in the same driver's context struct so having a release * callback in both is a bug. */ - WARN_ON(v4l2_dev_has_release && mdev_has_release); + WARN_ON(v4l2_dev_has_release && !mdev_has_ref); #endif /* * Decrease v4l2_device refcount, but only if the media device doesn't - * have a release callback. + * have a release callback. Otherwise one could expect accessing + * released memory --- driver's context struct refcounted already via + * struct media_device. */ if (v4l2_dev_has_release #ifdef CONFIG_MEDIA_CONTROLLER - && !mdev_has_release + && mdev_has_ref #endif ) v4l2_device_put(v4l2_dev); diff --git a/include/media/media-devnode.h b/include/media/media-devnode.h index 840f7ae852d3..85d54e2c9a97 100644 --- a/include/media/media-devnode.h +++ b/include/media/media-devnode.h @@ -41,8 +41,6 @@ struct media_devnode; * @compat_ioctl: pointer to the function that will handle 32 bits userspace * calls to the ioctl() syscall on a Kernel compiled with 64 bits. * @open: pointer to the function that implements open() syscall - * @release: pointer to the function that will release the resources allocated - * by the @open function. */ struct media_file_operations { struct module *owner; @@ -55,9 +53,56 @@ struct media_file_operations { int (*release) (struct file *); }; +/** + * struct media_devnode_cdev - Workaround for drivers not managing media device + * lifetime - character device + * + * Store the characeter device and whether this is a compatibility reference or + * not. struct media_devnode_cdev is embedded in either struct + * media_devnode_compat_ref or struct media_devnode. + * + * @cdev: the chracter device + * @is_compat_ref: Is this a compatibility reference or not? + */ +struct media_devnode_cdev { + struct cdev cdev; + bool is_compat_ref; +}; + +/** + * struct media_devnode_compat_ref - Workaround for drivers not managing media + * device lifetime - reference + * + * The purpose if this struct is to support drivers that do not manage the + * lifetime of their respective media devices to avoid the worst effects of + * this, namely an IOCTL call on an open file handle to a device that has been + * unbound causing a kernel oops systematically. This is not a fix. The proper, + * reliable way to handle this is to manage the resources used by the + * driver. This struct and its use can be removed once all drivers have been + * converted. + * + * @dev: struct device that remains in place as long as any reference remains + * @cdev: the related character device + * @devnode: a pointer back to the devnode + * @release: pointer to the function that will release the resources + * allocated by the @open function. + * @registered: is this device registered? + * @minor: the minor number of the media devnode + */ +struct media_devnode_compat_ref { + struct device dev; + struct media_devnode_cdev mcdev; + struct media_devnode *devnode; + int (*release)(struct file *); + atomic_t registered; + unsigned int minor; +}; + /** * struct media_devnode_fh - Media device node file handle * @devnode: pointer to the media device node + * @ref: media device compat ref, if the driver does not manage media + * device lifetime * * This structure serves as a base for per-file-handle data storage. Media * device node users embed media_devnode_fh in their custom file handle data @@ -67,6 +112,7 @@ struct media_file_operations { */ struct media_devnode_fh { struct media_devnode *devnode; + struct media_devnode_compat_ref *ref; }; /** @@ -80,6 +126,8 @@ struct media_devnode_fh { * @flags: flags, combination of the ``MEDIA_FLAG_*`` constants * @release: release callback called at the end of ``media_devnode_release()`` * routine at media-device.c. + * @ref: reference for providing best effort memory safety in device + * removal * * This structure represents a media-related device node. * @@ -92,7 +140,7 @@ struct media_devnode { /* sysfs */ struct device dev; /* media device */ - struct cdev cdev; /* character device */ + struct media_devnode_cdev mcdev; /* character device + compat status */ struct device *parent; /* device parent */ /* device info */ @@ -101,10 +149,18 @@ struct media_devnode { /* callbacks */ void (*release)(struct media_devnode *devnode); + + /* compat reference */ + struct media_devnode_compat_ref *ref; }; +static inline struct device *media_devnode_dev(struct media_devnode *devnode) +{ + return devnode->ref ? &devnode->ref->dev : &devnode->dev; +} + /* dev to media_devnode */ -#define to_media_devnode(cd) container_of(cd, struct media_devnode, dev) +struct media_devnode *to_media_devnode(struct device *dev); /** * media_devnode_init - initialise a media devnode