summaryrefslogtreecommitdiff
path: root/drivers/pci/hotplug
diff options
context:
space:
mode:
authorAlex Chiang <achiang@hp.com>2008-10-20 23:41:02 (GMT)
committerJesse Barnes <jbarnes@virtuousgeek.org>2008-10-22 23:42:39 (GMT)
commit5fe6cc60680d29740b85278e17a002fa27b7e642 (patch)
tree3815152b48be7f02bb13b765ea8784ff60bfffcb /drivers/pci/hotplug
parent95cb9093960b6249fdbe7417bf513a1358aaa51a (diff)
downloadlinux-5fe6cc60680d29740b85278e17a002fa27b7e642.tar.xz
PCI: prevent duplicate slot names
Prevent callers of pci_create_slot() from registering slots with duplicate names. This condition occurs most often when PCI hotplug drivers are loaded on platforms with broken firmware that assigns identical names to multiple slots. We now rename these duplicate slots on behalf of the user. If firmware assigns the name N to multiple slots, then: The first registered slot is assigned N The second registered slot is assigned N-1 The third registered slot is assigned N-2 etc. This is the permanent fix mentioned in earlier commits d6a9e9b4 and 167e782e (shpchp/pciehp: Rename duplicate slot name...). We take advantage of the new 'hotplug' parameter in pci_create_slot() to prevent a slot create/rename race between hotplug drivers and detection drivers. Scenario A: hotplug driver detection driver -------------- ---------------- pci_create_slot(hotplug=set) pci_create_slot(hotplug=NULL) The hotplug driver creates the slot with its desired name, and then releases the semaphore. Now, the detection driver tries to create the same slot, but it already exists. We don't care about renaming, so return the existing slot. Scenario B: hotplug driver detection driver -------------- ---------------- pci_create_slot(hotplug=NULL) pci_create_slot(hotplug=set) The detection driver creates the slot with name "X". Then the hotplug driver tries to create the same slot, but wants the name "Y" instead. We detect that we're trying to create the same slot and that we also want a rename, so rename the slot to "Y" and return. Scenario C: hotplug driver hotplug driver -------------- ---------------- pci_create_slot(hotplug=set) pci_create_slot(hotplug=set) Two separate hotplug drivers are attempting to claim the slot and are passing valid hotplug_slot args to pci_create_slot(). We detect that the slot already has a ->hotplug callback, prevent a rename, and return -EBUSY. Cc: kristen.c.accardi@intel.com Cc: matthew@wil.cx Acked-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> Signed-off-by: Alex Chiang <achiang@hp.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci/hotplug')
-rw-r--r--drivers/pci/hotplug/pci_hotplug_core.c26
-rw-r--r--drivers/pci/hotplug/pciehp_core.c15
-rw-r--r--drivers/pci/hotplug/shpchp_core.c15
3 files changed, 2 insertions, 54 deletions
diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
index e715248..a6f1f28 100644
--- a/drivers/pci/hotplug/pci_hotplug_core.c
+++ b/drivers/pci/hotplug/pci_hotplug_core.c
@@ -569,12 +569,6 @@ int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr,
mutex_lock(&pci_hp_mutex);
- /* Check if we have already registered a slot with the same name. */
- if (get_slot_from_name(name)) {
- result = -EEXIST;
- goto out;
- }
-
/*
* No problems if we call this interface from both ACPI_PCI_SLOT
* driver and call it here again. If we've already created the
@@ -583,27 +577,12 @@ int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr,
pci_slot = pci_create_slot(bus, slot_nr, name, slot);
if (IS_ERR(pci_slot)) {
result = PTR_ERR(pci_slot);
- goto cleanup;
- }
-
- if (pci_slot->hotplug) {
- dbg("%s: already claimed\n", __func__);
- result = -EBUSY;
- goto cleanup;
+ goto out;
}
slot->pci_slot = pci_slot;
pci_slot->hotplug = slot;
- /*
- * Allow pcihp drivers to override the ACPI_PCI_SLOT name.
- */
- if (strcmp(kobject_name(&pci_slot->kobj), name)) {
- result = kobject_rename(&pci_slot->kobj, name);
- if (result)
- goto cleanup;
- }
-
list_add(&slot->slot_list, &pci_hotplug_slot_list);
result = fs_add_slot(pci_slot);
@@ -612,9 +591,6 @@ int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr,
out:
mutex_unlock(&pci_hp_mutex);
return result;
-cleanup:
- pci_destroy_slot(pci_slot);
- goto out;
}
/**
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index 3ace5e0..af89d7b 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -196,7 +196,6 @@ static int init_slots(struct controller *ctrl)
struct slot *slot;
struct hotplug_slot *hotplug_slot;
struct hotplug_slot_info *info;
- int len, dup = 1;
int retval = -ENOMEM;
list_for_each_entry(slot, &ctrl->slot_list, slot_list) {
@@ -223,25 +222,11 @@ static int init_slots(struct controller *ctrl)
ctrl_dbg(ctrl, "Registering bus=%x dev=%x hp_slot=%x sun=%x "
"slot_device_offset=%x\n", slot->bus, slot->device,
slot->hp_slot, slot->number, ctrl->slot_device_offset);
-duplicate_name:
retval = pci_hp_register(hotplug_slot,
ctrl->pci_dev->subordinate,
slot->device,
slot->name);
if (retval) {
- /*
- * If slot N already exists, we'll try to create
- * slot N-1, N-2 ... N-M, until we overflow.
- */
- if (retval == -EEXIST) {
- len = snprintf(slot->name, SLOT_NAME_SIZE,
- "%d-%d", slot->number, dup++);
- if (len < SLOT_NAME_SIZE)
- goto duplicate_name;
- else
- ctrl_err(ctrl, "duplicate slot name "
- "overflow\n");
- }
ctrl_err(ctrl, "pci_hp_register failed with error %d\n",
retval);
goto error_info;
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
index bf50966..cfdd079 100644
--- a/drivers/pci/hotplug/shpchp_core.c
+++ b/drivers/pci/hotplug/shpchp_core.c
@@ -102,7 +102,7 @@ static int init_slots(struct controller *ctrl)
struct hotplug_slot *hotplug_slot;
struct hotplug_slot_info *info;
int retval = -ENOMEM;
- int i, len, dup = 1;
+ int i;
for (i = 0; i < ctrl->num_slots; i++) {
slot = kzalloc(sizeof(*slot), GFP_KERNEL);
@@ -144,23 +144,10 @@ static int init_slots(struct controller *ctrl)
dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x "
"slot_device_offset=%x\n", slot->bus, slot->device,
slot->hp_slot, slot->number, ctrl->slot_device_offset);
-duplicate_name:
retval = pci_hp_register(slot->hotplug_slot,
ctrl->pci_dev->subordinate, slot->device,
hotplug_slot->name);
if (retval) {
- /*
- * If slot N already exists, we'll try to create
- * slot N-1, N-2 ... N-M, until we overflow.
- */
- if (retval == -EEXIST) {
- len = snprintf(slot->name, SLOT_NAME_SIZE,
- "%d-%d", slot->number, dup++);
- if (len < SLOT_NAME_SIZE)
- goto duplicate_name;
- else
- err("duplicate slot name overflow\n");
- }
err("pci_hp_register failed with error %d\n", retval);
goto error_info;
}