diff options
author | Dave Peterson <dsp@llnl.gov> | 2006-03-26 04:38:50 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-26 11:57:07 -0500 |
commit | 18dbc337af5d6efd30cb9291e74722c8ad134fd3 (patch) | |
tree | 10163d19960173d29deb7a9d931dfcdfe2188975 /drivers/edac/edac_mc.c | |
parent | 472678ebd30d87cbe8d97562dcc0e46d1076040f (diff) |
[PATCH] EDAC: protect memory controller list
- Fix code so we always hold mem_ctls_mutex while we are stepping
through the list of mem_ctl_info structures. Otherwise bad things
may happen if one task is stepping through the list while another
task is modifying it. We may eventually want to use reference
counting to manage the mem_ctl_info structures. In the meantime we
may as well fix this bug.
- Don't disable interrupts while we are walking the list of
mem_ctl_info structures in check_mc_devices(). This is unnecessary.
Signed-off-by: David S. Peterson <dsp@llnl.gov>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/edac/edac_mc.c')
-rw-r--r-- | drivers/edac/edac_mc.c | 40 |
1 files changed, 18 insertions, 22 deletions
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 7ee9419234aa..ad812a4f8c99 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c | |||
@@ -1370,11 +1370,7 @@ void edac_mc_free(struct mem_ctl_info *mci) | |||
1370 | kfree(mci); | 1370 | kfree(mci); |
1371 | } | 1371 | } |
1372 | 1372 | ||
1373 | 1373 | static struct mem_ctl_info *find_mci_by_pdev(struct pci_dev *pdev) | |
1374 | |||
1375 | EXPORT_SYMBOL(edac_mc_find_mci_by_pdev); | ||
1376 | |||
1377 | struct mem_ctl_info *edac_mc_find_mci_by_pdev(struct pci_dev *pdev) | ||
1378 | { | 1374 | { |
1379 | struct mem_ctl_info *mci; | 1375 | struct mem_ctl_info *mci; |
1380 | struct list_head *item; | 1376 | struct list_head *item; |
@@ -1401,7 +1397,7 @@ static int add_mc_to_global_list (struct mem_ctl_info *mci) | |||
1401 | mci->mc_idx = 0; | 1397 | mci->mc_idx = 0; |
1402 | insert_before = &mc_devices; | 1398 | insert_before = &mc_devices; |
1403 | } else { | 1399 | } else { |
1404 | if (edac_mc_find_mci_by_pdev(mci->pdev)) { | 1400 | if (find_mci_by_pdev(mci->pdev)) { |
1405 | edac_printk(KERN_WARNING, EDAC_MC, | 1401 | edac_printk(KERN_WARNING, EDAC_MC, |
1406 | "%s (%s) %s %s already assigned %d\n", | 1402 | "%s (%s) %s %s already assigned %d\n", |
1407 | mci->pdev->dev.bus_id, | 1403 | mci->pdev->dev.bus_id, |
@@ -1520,27 +1516,29 @@ EXPORT_SYMBOL(edac_mc_del_mc); | |||
1520 | /** | 1516 | /** |
1521 | * edac_mc_del_mc: Remove sysfs entries for specified mci structure and | 1517 | * edac_mc_del_mc: Remove sysfs entries for specified mci structure and |
1522 | * remove mci structure from global list | 1518 | * remove mci structure from global list |
1523 | * @mci: Pointer to struct mem_ctl_info structure | 1519 | * @pdev: Pointer to 'struct pci_dev' representing mci structure to remove. |
1524 | * | 1520 | * |
1525 | * Returns: | 1521 | * Return pointer to removed mci structure, or NULL if device not found. |
1526 | * 0 Success | ||
1527 | * 1 Failure | ||
1528 | */ | 1522 | */ |
1529 | int edac_mc_del_mc(struct mem_ctl_info *mci) | 1523 | struct mem_ctl_info * edac_mc_del_mc(struct pci_dev *pdev) |
1530 | { | 1524 | { |
1531 | int rc = 1; | 1525 | struct mem_ctl_info *mci; |
1532 | 1526 | ||
1533 | debugf0("MC%d: %s()\n", mci->mc_idx, __func__); | 1527 | debugf0("MC: %s()\n", __func__); |
1534 | edac_remove_sysfs_mci_device(mci); | ||
1535 | down(&mem_ctls_mutex); | 1528 | down(&mem_ctls_mutex); |
1529 | |||
1530 | if ((mci = find_mci_by_pdev(pdev)) == NULL) { | ||
1531 | up(&mem_ctls_mutex); | ||
1532 | return NULL; | ||
1533 | } | ||
1534 | |||
1535 | edac_remove_sysfs_mci_device(mci); | ||
1536 | del_mc_from_global_list(mci); | 1536 | del_mc_from_global_list(mci); |
1537 | up(&mem_ctls_mutex); | ||
1537 | edac_printk(KERN_INFO, EDAC_MC, | 1538 | edac_printk(KERN_INFO, EDAC_MC, |
1538 | "Removed device %d for %s %s: PCI %s\n", mci->mc_idx, | 1539 | "Removed device %d for %s %s: PCI %s\n", mci->mc_idx, |
1539 | mci->mod_name, mci->ctl_name, pci_name(mci->pdev)); | 1540 | mci->mod_name, mci->ctl_name, pci_name(mci->pdev)); |
1540 | rc = 0; | 1541 | return mci; |
1541 | up(&mem_ctls_mutex); | ||
1542 | |||
1543 | return rc; | ||
1544 | } | 1542 | } |
1545 | 1543 | ||
1546 | 1544 | ||
@@ -2018,14 +2016,12 @@ static inline void clear_pci_parity_errors(void) | |||
2018 | */ | 2016 | */ |
2019 | static inline void check_mc_devices (void) | 2017 | static inline void check_mc_devices (void) |
2020 | { | 2018 | { |
2021 | unsigned long flags; | ||
2022 | struct list_head *item; | 2019 | struct list_head *item; |
2023 | struct mem_ctl_info *mci; | 2020 | struct mem_ctl_info *mci; |
2024 | 2021 | ||
2025 | debugf3("%s()\n", __func__); | 2022 | debugf3("%s()\n", __func__); |
2026 | 2023 | ||
2027 | /* during poll, have interrupts off */ | 2024 | down(&mem_ctls_mutex); |
2028 | local_irq_save(flags); | ||
2029 | 2025 | ||
2030 | list_for_each(item, &mc_devices) { | 2026 | list_for_each(item, &mc_devices) { |
2031 | mci = list_entry(item, struct mem_ctl_info, link); | 2027 | mci = list_entry(item, struct mem_ctl_info, link); |
@@ -2034,7 +2030,7 @@ static inline void check_mc_devices (void) | |||
2034 | mci->edac_check(mci); | 2030 | mci->edac_check(mci); |
2035 | } | 2031 | } |
2036 | 2032 | ||
2037 | local_irq_restore(flags); | 2033 | up(&mem_ctls_mutex); |
2038 | } | 2034 | } |
2039 | 2035 | ||
2040 | 2036 | ||