linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/2] HID: ensure timely release of driver resources
@ 2023-05-23 21:04 Dmitry Torokhov
  2023-05-23 21:04 ` [PATCH v2 1/2] HID: split apart hid_device_probe to make logic more apparent Dmitry Torokhov
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Dmitry Torokhov @ 2023-05-23 21:04 UTC (permalink / raw)
  To: Jiri Kosina, Benjamin Tissoires; +Cc: linux-input, linux-kernel, Stephen Boyd

These 2 patches address an issue in HID subsystem where cleanup code in
the bus code runs before releasing devres-managed resources by the
driver core.

This is a V2 of the patch, which was split in 2 parts - generic cleanup
and the actualy change addressing the issue.

Link: https://lore.kernel.org/r/20230505232417.1377393-1-swboyd@chromium.org
Link: https://lore.kernel.org/r/ZFWarGkRAfPOmI6E@google.com
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
Dmitry Torokhov (2):
      HID: split apart hid_device_probe to make logic more apparent
      HID: ensure timely release of driver-allocated resources

 drivers/hid/hid-core.c | 118 +++++++++++++++++++++++++++++--------------------
 include/linux/hid.h    |   1 +
 2 files changed, 72 insertions(+), 47 deletions(-)
---
base-commit: 9f925874281f7e8855855d6210d6e29d844e4307
change-id: 20230523-hid-devres-b0edd05de354

Best regards,
-- 
Dmitry


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH v2 1/2] HID: split apart hid_device_probe to make logic more apparent
  2023-05-23 21:04 [PATCH v2 0/2] HID: ensure timely release of driver resources Dmitry Torokhov
@ 2023-05-23 21:04 ` Dmitry Torokhov
  2023-05-23 21:04 ` [PATCH v2 2/2] HID: ensure timely release of driver-allocated resources Dmitry Torokhov
  2023-05-26 18:46 ` [PATCH v2 0/2] HID: ensure timely release of driver resources Jiri Kosina
  2 siblings, 0 replies; 4+ messages in thread
From: Dmitry Torokhov @ 2023-05-23 21:04 UTC (permalink / raw)
  To: Jiri Kosina, Benjamin Tissoires; +Cc: linux-input, linux-kernel, Stephen Boyd

hid_device_probe() has a complex flow and locks and unlocks a mutex.
Move the most of the logic into __hid_device_probe() and
hid_check_device_match() and leave the locking in hid_device_probe()
which makes the code more clear.

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
 drivers/hid/hid-core.c | 101 ++++++++++++++++++++++++++-----------------------
 1 file changed, 54 insertions(+), 47 deletions(-)

diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 22623eb4f72f..1f0bb2784bfc 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -2587,64 +2587,71 @@ bool hid_compare_device_paths(struct hid_device *hdev_a,
 }
 EXPORT_SYMBOL_GPL(hid_compare_device_paths);
 
+static bool hid_check_device_match(struct hid_device *hdev,
+				   struct hid_driver *hdrv,
+				   const struct hid_device_id **id)
+{
+	*id = hid_match_device(hdev, hdrv);
+	if (!*id)
+		return -ENODEV;
+
+	if (hdrv->match)
+		return hdrv->match(hdev, hid_ignore_special_drivers);
+
+	/*
+	 * hid-generic implements .match(), so we must be dealing with a
+	 * different HID driver here, and can simply check if
+	 * hid_ignore_special_drivers is set or not.
+	 */
+	return !hid_ignore_special_drivers;
+}
+
+static int __hid_device_probe(struct hid_device *hdev, struct hid_driver *hdrv)
+{
+	const struct hid_device_id *id;
+	int ret;
+
+	if (!hid_check_device_match(hdev, hdrv, &id))
+		return -ENODEV;
+
+	/* reset the quirks that has been previously set */
+	hdev->quirks = hid_lookup_quirk(hdev);
+	hdev->driver = hdrv;
+
+	if (hdrv->probe) {
+		ret = hdrv->probe(hdev, id);
+	} else { /* default probe */
+		ret = hid_open_report(hdev);
+		if (!ret)
+			ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+	}
+
+	if (ret) {
+		hid_close_report(hdev);
+		hdev->driver = NULL;
+	}
+
+	return ret;
+}
+
 static int hid_device_probe(struct device *dev)
 {
-	struct hid_driver *hdrv = to_hid_driver(dev->driver);
 	struct hid_device *hdev = to_hid_device(dev);
-	const struct hid_device_id *id;
+	struct hid_driver *hdrv = to_hid_driver(dev->driver);
 	int ret = 0;
 
-	if (down_interruptible(&hdev->driver_input_lock)) {
-		ret = -EINTR;
-		goto end;
-	}
-	hdev->io_started = false;
+	if (down_interruptible(&hdev->driver_input_lock))
+		return -EINTR;
 
+	hdev->io_started = false;
 	clear_bit(ffs(HID_STAT_REPROBED), &hdev->status);
 
-	if (!hdev->driver) {
-		id = hid_match_device(hdev, hdrv);
-		if (id == NULL) {
-			ret = -ENODEV;
-			goto unlock;
-		}
+	if (!hdev->driver)
+		ret = __hid_device_probe(hdev, hdrv);
 
-		if (hdrv->match) {
-			if (!hdrv->match(hdev, hid_ignore_special_drivers)) {
-				ret = -ENODEV;
-				goto unlock;
-			}
-		} else {
-			/*
-			 * hid-generic implements .match(), so if
-			 * hid_ignore_special_drivers is set, we can safely
-			 * return.
-			 */
-			if (hid_ignore_special_drivers) {
-				ret = -ENODEV;
-				goto unlock;
-			}
-		}
-
-		/* reset the quirks that has been previously set */
-		hdev->quirks = hid_lookup_quirk(hdev);
-		hdev->driver = hdrv;
-		if (hdrv->probe) {
-			ret = hdrv->probe(hdev, id);
-		} else { /* default probe */
-			ret = hid_open_report(hdev);
-			if (!ret)
-				ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
-		}
-		if (ret) {
-			hid_close_report(hdev);
-			hdev->driver = NULL;
-		}
-	}
-unlock:
 	if (!hdev->io_started)
 		up(&hdev->driver_input_lock);
-end:
+
 	return ret;
 }
 

-- 
2.40.1.698.g37aff9b760-goog


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v2 2/2] HID: ensure timely release of driver-allocated resources
  2023-05-23 21:04 [PATCH v2 0/2] HID: ensure timely release of driver resources Dmitry Torokhov
  2023-05-23 21:04 ` [PATCH v2 1/2] HID: split apart hid_device_probe to make logic more apparent Dmitry Torokhov
@ 2023-05-23 21:04 ` Dmitry Torokhov
  2023-05-26 18:46 ` [PATCH v2 0/2] HID: ensure timely release of driver resources Jiri Kosina
  2 siblings, 0 replies; 4+ messages in thread
From: Dmitry Torokhov @ 2023-05-23 21:04 UTC (permalink / raw)
  To: Jiri Kosina, Benjamin Tissoires; +Cc: linux-input, linux-kernel, Stephen Boyd

More and more drivers rely on devres to manage their resources, however
if bus' probe() and release() methods are not trivial and control some
of resources as well (for example enable or disable clocks, or attach
device to a power domain), we need to make sure that driver-allocated
resources are released immediately after driver's remove() method
returns, and not postponed until driver core gets around to releasing
resources.

In case of HID we should not try to close the report and release
associated memory until after all devres callbacks are executed. To fix
that we open a new devres group before calling driver's probe() and
explicitly release it when we return from driver's remove().

This is similar to what we did for I2C bus in commit 5b5475826c52 ("i2c:
ensure timely release of driver-allocated resources"). It is tempting to
try and move this into driver core, but actually doing so is challenging,
we need to split bus' remove() method into pre- and post-remove methods,
which would make the logic even less clear.

Reported-by: Stephen Boyd <swboyd@chromium.org>
Link: https://lore.kernel.org/r/20230505232417.1377393-1-swboyd@chromium.org
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
 drivers/hid/hid-core.c | 17 +++++++++++++++++
 include/linux/hid.h    |  1 +
 2 files changed, 18 insertions(+)

diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 1f0bb2784bfc..4b7062dcefec 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -2614,6 +2614,10 @@ static int __hid_device_probe(struct hid_device *hdev, struct hid_driver *hdrv)
 	if (!hid_check_device_match(hdev, hdrv, &id))
 		return -ENODEV;
 
+	hdev->devres_group_id = devres_open_group(&hdev->dev, NULL, GFP_KERNEL);
+	if (!hdev->devres_group_id)
+		return -ENOMEM;
+
 	/* reset the quirks that has been previously set */
 	hdev->quirks = hid_lookup_quirk(hdev);
 	hdev->driver = hdrv;
@@ -2626,7 +2630,16 @@ static int __hid_device_probe(struct hid_device *hdev, struct hid_driver *hdrv)
 			ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 	}
 
+	/*
+	 * Note that we are not closing the devres group opened above so
+	 * even resources that were attached to the device after probe is
+	 * run are released when hid_device_remove() is executed. This is
+	 * needed as some drivers would allocate additional resources,
+	 * for example when updating firmware.
+	 */
+
 	if (ret) {
+		devres_release_group(&hdev->dev, hdev->devres_group_id);
 		hid_close_report(hdev);
 		hdev->driver = NULL;
 	}
@@ -2669,6 +2682,10 @@ static void hid_device_remove(struct device *dev)
 			hdrv->remove(hdev);
 		else /* default remove */
 			hid_hw_stop(hdev);
+
+		/* Release all devres resources allocated by the driver */
+		devres_release_group(&hdev->dev, hdev->devres_group_id);
+
 		hid_close_report(hdev);
 		hdev->driver = NULL;
 	}
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 4e4c4fe36911..39e21e3815ad 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -597,6 +597,7 @@ struct hid_device {							/* device report descriptor */
 	struct semaphore driver_input_lock;				/* protects the current driver */
 	struct device dev;						/* device */
 	struct hid_driver *driver;
+	void *devres_group_id;						/* ID of probe devres group	*/
 
 	const struct hid_ll_driver *ll_driver;
 	struct mutex ll_open_lock;

-- 
2.40.1.698.g37aff9b760-goog


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH v2 0/2] HID: ensure timely release of driver resources
  2023-05-23 21:04 [PATCH v2 0/2] HID: ensure timely release of driver resources Dmitry Torokhov
  2023-05-23 21:04 ` [PATCH v2 1/2] HID: split apart hid_device_probe to make logic more apparent Dmitry Torokhov
  2023-05-23 21:04 ` [PATCH v2 2/2] HID: ensure timely release of driver-allocated resources Dmitry Torokhov
@ 2023-05-26 18:46 ` Jiri Kosina
  2 siblings, 0 replies; 4+ messages in thread
From: Jiri Kosina @ 2023-05-26 18:46 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Benjamin Tissoires, linux-input, linux-kernel, Stephen Boyd

On Tue, 23 May 2023, Dmitry Torokhov wrote:

> These 2 patches address an issue in HID subsystem where cleanup code in
> the bus code runs before releasing devres-managed resources by the
> driver core.
> 
> This is a V2 of the patch, which was split in 2 parts - generic cleanup
> and the actualy change addressing the issue.
> 
> Link: https://lore.kernel.org/r/20230505232417.1377393-1-swboyd@chromium.org
> Link: https://lore.kernel.org/r/ZFWarGkRAfPOmI6E@google.com
> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> ---
> Dmitry Torokhov (2):
>       HID: split apart hid_device_probe to make logic more apparent
>       HID: ensure timely release of driver-allocated resources
> 
>  drivers/hid/hid-core.c | 118 +++++++++++++++++++++++++++++--------------------
>  include/linux/hid.h    |   1 +
>  2 files changed, 72 insertions(+), 47 deletions(-)

Now queued in hid.git#for-6.5/core.

Thanks,

-- 
Jiri Kosina
SUSE Labs


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2023-05-26 18:46 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-05-23 21:04 [PATCH v2 0/2] HID: ensure timely release of driver resources Dmitry Torokhov
2023-05-23 21:04 ` [PATCH v2 1/2] HID: split apart hid_device_probe to make logic more apparent Dmitry Torokhov
2023-05-23 21:04 ` [PATCH v2 2/2] HID: ensure timely release of driver-allocated resources Dmitry Torokhov
2023-05-26 18:46 ` [PATCH v2 0/2] HID: ensure timely release of driver resources Jiri Kosina

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).