| From 9b33ed3a4be3985e11c6bc81e5789262794164b6 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Mon, 12 Jul 2021 21:21:21 +0300 |
| Subject: ACPI: utils: Fix reference counting in for_each_acpi_dev_match() |
| |
| From: Andy Shevchenko <andy.shevchenko@gmail.com> |
| |
| [ Upstream commit 71f6428332844f38c7cb10461d9f29e9c9b983a0 ] |
| |
| Currently it's possible to iterate over the dangling pointer in case the device |
| suddenly disappears. This may happen becase callers put it at the end of a loop. |
| |
| Instead, let's move that call inside acpi_dev_get_next_match_dev(). |
| |
| Fixes: 803abec64ef9 ("media: ipu3-cio2: Add cio2-bridge to ipu3-cio2 driver") |
| Fixes: bf263f64e804 ("media: ACPI / bus: Add acpi_dev_get_next_match_dev() and helper macro") |
| Fixes: edbd1bc4951e ("efi/dev-path-parser: Switch to use for_each_acpi_dev_match()") |
| Signed-off-by: Andy Shevchenko <andy.shevchenko@gmail.com> |
| Reviewed-by: Daniel Scally <djrscally@gmail.com> |
| Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/acpi/utils.c | 7 +++---- |
| drivers/firmware/efi/dev-path-parser.c | 1 - |
| drivers/media/pci/intel/ipu3/cio2-bridge.c | 6 ++---- |
| include/acpi/acpi_bus.h | 5 ----- |
| 4 files changed, 5 insertions(+), 14 deletions(-) |
| |
| diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c |
| index 3b54b8fd7396..27ec9d57f3b8 100644 |
| --- a/drivers/acpi/utils.c |
| +++ b/drivers/acpi/utils.c |
| @@ -846,11 +846,9 @@ EXPORT_SYMBOL(acpi_dev_present); |
| * Return the next match of ACPI device if another matching device was present |
| * at the moment of invocation, or NULL otherwise. |
| * |
| - * FIXME: The function does not tolerate the sudden disappearance of @adev, e.g. |
| - * in the case of a hotplug event. That said, the caller should ensure that |
| - * this will never happen. |
| - * |
| * The caller is responsible for invoking acpi_dev_put() on the returned device. |
| + * On the other hand the function invokes acpi_dev_put() on the given @adev |
| + * assuming that its reference counter had been increased beforehand. |
| * |
| * See additional information in acpi_dev_present() as well. |
| */ |
| @@ -866,6 +864,7 @@ acpi_dev_get_next_match_dev(struct acpi_device *adev, const char *hid, const cha |
| match.hrv = hrv; |
| |
| dev = bus_find_device(&acpi_bus_type, start, &match, acpi_dev_match_cb); |
| + acpi_dev_put(adev); |
| return dev ? to_acpi_device(dev) : NULL; |
| } |
| EXPORT_SYMBOL(acpi_dev_get_next_match_dev); |
| diff --git a/drivers/firmware/efi/dev-path-parser.c b/drivers/firmware/efi/dev-path-parser.c |
| index 10d4457417a4..eb9c65f97841 100644 |
| --- a/drivers/firmware/efi/dev-path-parser.c |
| +++ b/drivers/firmware/efi/dev-path-parser.c |
| @@ -34,7 +34,6 @@ static long __init parse_acpi_path(const struct efi_dev_path *node, |
| break; |
| if (!adev->pnp.unique_id && node->acpi.uid == 0) |
| break; |
| - acpi_dev_put(adev); |
| } |
| if (!adev) |
| return -ENODEV; |
| diff --git a/drivers/media/pci/intel/ipu3/cio2-bridge.c b/drivers/media/pci/intel/ipu3/cio2-bridge.c |
| index 4657e99df033..59a36f922675 100644 |
| --- a/drivers/media/pci/intel/ipu3/cio2-bridge.c |
| +++ b/drivers/media/pci/intel/ipu3/cio2-bridge.c |
| @@ -173,10 +173,8 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg, |
| int ret; |
| |
| for_each_acpi_dev_match(adev, cfg->hid, NULL, -1) { |
| - if (!adev->status.enabled) { |
| - acpi_dev_put(adev); |
| + if (!adev->status.enabled) |
| continue; |
| - } |
| |
| if (bridge->n_sensors >= CIO2_NUM_PORTS) { |
| acpi_dev_put(adev); |
| @@ -185,7 +183,6 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg, |
| } |
| |
| sensor = &bridge->sensors[bridge->n_sensors]; |
| - sensor->adev = adev; |
| strscpy(sensor->name, cfg->hid, sizeof(sensor->name)); |
| |
| ret = cio2_bridge_read_acpi_buffer(adev, "SSDB", |
| @@ -215,6 +212,7 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg, |
| goto err_free_swnodes; |
| } |
| |
| + sensor->adev = acpi_dev_get(adev); |
| adev->fwnode.secondary = fwnode; |
| |
| dev_info(&cio2->dev, "Found supported sensor %s\n", |
| diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h |
| index 3a82faac5767..bff6a11bb21f 100644 |
| --- a/include/acpi/acpi_bus.h |
| +++ b/include/acpi/acpi_bus.h |
| @@ -698,11 +698,6 @@ acpi_dev_get_first_match_dev(const char *hid, const char *uid, s64 hrv); |
| * @hrv: Hardware Revision of the device, pass -1 to not check _HRV |
| * |
| * The caller is responsible for invoking acpi_dev_put() on the returned device. |
| - * |
| - * FIXME: Due to above requirement there is a window that may invalidate @adev |
| - * and next iteration will use a dangling pointer, e.g. in the case of a |
| - * hotplug event. That said, the caller should ensure that this will never |
| - * happen. |
| */ |
| #define for_each_acpi_dev_match(adev, hid, uid, hrv) \ |
| for (adev = acpi_dev_get_first_match_dev(hid, uid, hrv); \ |
| -- |
| 2.30.2 |
| |