ACPI: utils: Fix reference counting in for_each_acpi_dev_match()
authorAndy Shevchenko <andy.shevchenko@gmail.com>
Mon, 12 Jul 2021 18:21:21 +0000 (21:21 +0300)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 19 Jul 2021 14:22:01 +0000 (16:22 +0200)
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>
drivers/acpi/utils.c
drivers/firmware/efi/dev-path-parser.c
drivers/media/pci/intel/ipu3/cio2-bridge.c
include/acpi/acpi_bus.h

index e7ddd281afff7f6ed9964c52e042e8d8393cf89a..d5cedffeeff915b7b571ae08a9298c26a3772015 100644 (file)
@@ -860,11 +860,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.
  */
@@ -880,6 +878,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);
index 10d4457417a4ff6a3e42b6d2c39309acd8dae630..eb9c65f978419951329b9e02431c975bcceee052 100644 (file)
@@ -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;
index 4657e99df0339ed3a94e8541b730b0727f4642af..59a36f92267555175db081310b3a32c0b0052c6b 100644 (file)
@@ -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",
index 1ae993fee4a5d479a2d659c29bbe1dad85a1e2a1..b9d434a936320bdbfaadd4d6a2ee14e45d383811 100644 (file)
@@ -707,11 +707,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);        \