PCI/sysfs: Decouple acpi_index from the optional device name element

The "_DSM for Naming a PCI or PCI Express Device Under Operating Systems"
(PCI Firmware r3.3, sec 4.6.7) returns a package of two elements:

  1) Instance number (mandatory Integer)
  2) String name (optional String, null string if not populated)

These are exposed as sysfs 'acpi_index' and 'label'. Previously, if
the name was malformed, reads of 'acpi_index' failed unnecessarily.

Validate each element only for the attribute that exports it.  So
"acpi_index" now depends on the instance number alone, and "label" reads
fail with -EIO when the name element is neither a string nor a buffer.  The
package elements pointer is read only after the object type has been
checked.

On platforms with a valid instance number and a malformed name element the
"acpi_index" attribute starts returning data.  Because udev derives the
onboard interface name from "acpi_index", an interface on such a platform
may be renamed once, on the first boot after this change.  That is the
attribute assuming the value the firmware always provided.

Link: https://github.com/pciutils/pciutils/issues/175
Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
[bhelgaas: commit log]
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Link: https://patch.msgid.link/20260814070522.2327975-3-kwilczynski@kernel.org
This commit is contained in:
Krzysztof Wilczyński 2026-08-14 07:05:20 +00:00 committed by Bjorn Helgaas
parent 36f9bd0992
commit 337bdf8531

View File

@ -157,7 +157,7 @@ static int dsm_get_label(struct device *dev, char *buf,
{
acpi_handle handle = ACPI_HANDLE(dev);
union acpi_object *obj, *tmp;
int len = 0;
int len;
if (!handle)
return -ENODEV;
@ -167,30 +167,43 @@ static int dsm_get_label(struct device *dev, char *buf,
if (!obj)
return -EIO;
tmp = obj->package.elements;
if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 2 &&
tmp[0].type == ACPI_TYPE_INTEGER &&
(tmp[1].type == ACPI_TYPE_STRING ||
tmp[1].type == ACPI_TYPE_BUFFER)) {
/*
* The second string element is optional even when
* this _DSM is implemented; when not implemented,
* this entry must return a null string.
*/
if (attr == ACPI_ATTR_INDEX_SHOW) {
len = sysfs_emit(buf, "%llu\n", tmp->integer.value);
} else if (attr == ACPI_ATTR_LABEL_SHOW) {
if (tmp[1].type == ACPI_TYPE_STRING)
len = sysfs_emit(buf, "%s\n",
tmp[1].string.pointer);
else if (tmp[1].type == ACPI_TYPE_BUFFER)
len = dsm_label_utf16s_to_utf8s(tmp + 1, buf);
}
if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 2) {
len = -EIO;
goto out;
}
tmp = obj->package.elements;
if (tmp[0].type != ACPI_TYPE_INTEGER) {
len = -EIO;
goto out;
}
if (attr == ACPI_ATTR_INDEX_SHOW) {
len = sysfs_emit(buf, "%llu\n", tmp[0].integer.value);
goto out;
}
/*
* Per PCI Firmware r3.3, sec 4.6.7, the device name is optional
* even when this _DSM is implemented. When not implemented, this
* entry must return a NULL string.
*/
switch (tmp[1].type) {
case ACPI_TYPE_STRING:
len = sysfs_emit(buf, "%s\n", tmp[1].string.pointer);
break;
case ACPI_TYPE_BUFFER:
len = dsm_label_utf16s_to_utf8s(&tmp[1], buf);
break;
default:
len = -EIO;
break;
}
out:
ACPI_FREE(obj);
return len > 0 ? len : -EIO;
return len;
}
static ssize_t label_show(struct device *dev, struct device_attribute *attr,