Skip to content

Commit 62c68e7

Browse files
dtorJiri Kosina
authored andcommitted
HID: ensure timely release of driver-allocated resources
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 5b54758 ("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 <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Dmitry Torokhov <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent 207733f commit 62c68e7

File tree

2 files changed

+18
-0
lines changed

2 files changed

+18
-0
lines changed

drivers/hid/hid-core.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2614,6 +2614,10 @@ static int __hid_device_probe(struct hid_device *hdev, struct hid_driver *hdrv)
26142614
if (!hid_check_device_match(hdev, hdrv, &id))
26152615
return -ENODEV;
26162616

2617+
hdev->devres_group_id = devres_open_group(&hdev->dev, NULL, GFP_KERNEL);
2618+
if (!hdev->devres_group_id)
2619+
return -ENOMEM;
2620+
26172621
/* reset the quirks that has been previously set */
26182622
hdev->quirks = hid_lookup_quirk(hdev);
26192623
hdev->driver = hdrv;
@@ -2626,7 +2630,16 @@ static int __hid_device_probe(struct hid_device *hdev, struct hid_driver *hdrv)
26262630
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
26272631
}
26282632

2633+
/*
2634+
* Note that we are not closing the devres group opened above so
2635+
* even resources that were attached to the device after probe is
2636+
* run are released when hid_device_remove() is executed. This is
2637+
* needed as some drivers would allocate additional resources,
2638+
* for example when updating firmware.
2639+
*/
2640+
26292641
if (ret) {
2642+
devres_release_group(&hdev->dev, hdev->devres_group_id);
26302643
hid_close_report(hdev);
26312644
hdev->driver = NULL;
26322645
}
@@ -2669,6 +2682,10 @@ static void hid_device_remove(struct device *dev)
26692682
hdrv->remove(hdev);
26702683
else /* default remove */
26712684
hid_hw_stop(hdev);
2685+
2686+
/* Release all devres resources allocated by the driver */
2687+
devres_release_group(&hdev->dev, hdev->devres_group_id);
2688+
26722689
hid_close_report(hdev);
26732690
hdev->driver = NULL;
26742691
}

include/linux/hid.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,7 @@ struct hid_device { /* device report descriptor */
597597
struct semaphore driver_input_lock; /* protects the current driver */
598598
struct device dev; /* device */
599599
struct hid_driver *driver;
600+
void *devres_group_id; /* ID of probe devres group */
600601

601602
const struct hid_ll_driver *ll_driver;
602603
struct mutex ll_open_lock;

0 commit comments

Comments
 (0)