diff options
-rw-r--r-- | drivers/pci/pci-sysfs.c | 24 |
1 files changed, 18 insertions, 6 deletions
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 94d1cb819eb6..c91e6c18debc 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c | |||
@@ -352,20 +352,32 @@ static struct device_attribute dev_rescan_attr = __ATTR(rescan, | |||
352 | (S_IWUSR|S_IWGRP), | 352 | (S_IWUSR|S_IWGRP), |
353 | NULL, dev_rescan_store); | 353 | NULL, dev_rescan_store); |
354 | 354 | ||
355 | static void remove_callback(struct device *dev) | ||
356 | { | ||
357 | struct pci_dev *pdev = to_pci_dev(dev); | ||
358 | |||
359 | mutex_lock(&pci_remove_rescan_mutex); | ||
360 | pci_stop_and_remove_bus_device(pdev); | ||
361 | mutex_unlock(&pci_remove_rescan_mutex); | ||
362 | } | ||
363 | |||
355 | static ssize_t | 364 | static ssize_t |
356 | remove_store(struct device *dev, struct device_attribute *attr, | 365 | remove_store(struct device *dev, struct device_attribute *dummy, |
357 | const char *buf, size_t count) | 366 | const char *buf, size_t count) |
358 | { | 367 | { |
368 | int ret = 0; | ||
359 | unsigned long val; | 369 | unsigned long val; |
360 | 370 | ||
361 | if (kstrtoul(buf, 0, &val) < 0) | 371 | if (kstrtoul(buf, 0, &val) < 0) |
362 | return -EINVAL; | 372 | return -EINVAL; |
363 | 373 | ||
364 | if (val && device_remove_file_self(dev, attr)) { | 374 | /* An attribute cannot be unregistered by one of its own methods, |
365 | mutex_lock(&pci_remove_rescan_mutex); | 375 | * so we have to use this roundabout approach. |
366 | pci_stop_and_remove_bus_device(to_pci_dev(dev)); | 376 | */ |
367 | mutex_unlock(&pci_remove_rescan_mutex); | 377 | if (val) |
368 | } | 378 | ret = device_schedule_callback(dev, remove_callback); |
379 | if (ret) | ||
380 | count = ret; | ||
369 | return count; | 381 | return count; |
370 | } | 382 | } |
371 | static struct device_attribute dev_remove_attr = __ATTR(remove, | 383 | static struct device_attribute dev_remove_attr = __ATTR(remove, |