[PATCH] EDAC: protect memory controller list
authorDave Peterson <dsp@llnl.gov>
Sun, 26 Mar 2006 09:38:50 +0000 (01:38 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Sun, 26 Mar 2006 16:57:07 +0000 (08:57 -0800)
- 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>
drivers/edac/amd76x_edac.c
drivers/edac/e752x_edac.c
drivers/edac/e7xxx_edac.c
drivers/edac/edac_mc.c
drivers/edac/edac_mc.h
drivers/edac/i82860_edac.c
drivers/edac/i82875p_edac.c
drivers/edac/r82600_edac.c

index 821c252d414cb8c18c566a51a99d1c724cf0524b..87bd8b4d561ff240bc25860945f127690dfeebfc 100644 (file)
@@ -314,10 +314,9 @@ static void __devexit amd76x_remove_one(struct pci_dev *pdev)
 
        debugf0("%s()\n", __func__);
 
-       if ((mci = edac_mc_find_mci_by_pdev(pdev)) == NULL)
-               return;
-       if (edac_mc_del_mc(mci))
+       if ((mci = edac_mc_del_mc(pdev)) == NULL)
                return;
+
        edac_mc_free(mci);
 }
 
index 24446542d8d61970a87463574aa1f7a1ed2e85f9..c86db23d3af3bfb782f24085892870a3a5459188 100644 (file)
@@ -976,10 +976,7 @@ static void __devexit e752x_remove_one(struct pci_dev *pdev)
 
        debugf0("%s()\n", __func__);
 
-       if ((mci = edac_mc_find_mci_by_pdev(pdev)) == NULL)
-               return;
-
-       if (edac_mc_del_mc(mci))
+       if ((mci = edac_mc_del_mc(pdev)) == NULL)
                return;
 
        pvt = (struct e752x_pvt *) mci->pvt_info;
index 8b0da35ae47c83328e72838b5ba59a236b7ae3a7..9b59c661f45e6539f57321a0d6340c532930ae6f 100644 (file)
@@ -510,12 +510,12 @@ static void __devexit e7xxx_remove_one(struct pci_dev *pdev)
 
        debugf0("%s()\n", __func__);
 
-       if (((mci = edac_mc_find_mci_by_pdev(pdev)) != 0) &&
-           !edac_mc_del_mc(mci)) {
-               pvt = (struct e7xxx_pvt *) mci->pvt_info;
-               pci_dev_put(pvt->bridge_ck);
-               edac_mc_free(mci);
-       }
+       if ((mci = edac_mc_del_mc(pdev)) == NULL)
+               return;
+
+       pvt = (struct e7xxx_pvt *) mci->pvt_info;
+       pci_dev_put(pvt->bridge_ck);
+       edac_mc_free(mci);
 }
 
 
index 7ee9419234aa29ff32d7930b11b572f85d202abc..ad812a4f8c9944bd3fb27b8cfa335882fa2f8268 100644 (file)
@@ -1370,11 +1370,7 @@ void edac_mc_free(struct mem_ctl_info *mci)
        kfree(mci);
 }
 
-
-
-EXPORT_SYMBOL(edac_mc_find_mci_by_pdev);
-
-struct mem_ctl_info *edac_mc_find_mci_by_pdev(struct pci_dev *pdev)
+static struct mem_ctl_info *find_mci_by_pdev(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
        struct list_head *item;
@@ -1401,7 +1397,7 @@ static int add_mc_to_global_list (struct mem_ctl_info *mci)
                mci->mc_idx = 0;
                insert_before = &mc_devices;
        } else {
-               if (edac_mc_find_mci_by_pdev(mci->pdev)) {
+               if (find_mci_by_pdev(mci->pdev)) {
                        edac_printk(KERN_WARNING, EDAC_MC,
                                "%s (%s) %s %s already assigned %d\n",
                                mci->pdev->dev.bus_id,
@@ -1520,27 +1516,29 @@ EXPORT_SYMBOL(edac_mc_del_mc);
 /**
  * edac_mc_del_mc: Remove sysfs entries for specified mci structure and
  *                 remove mci structure from global list
- * @mci:       Pointer to struct mem_ctl_info structure
+ * @pdev: Pointer to 'struct pci_dev' representing mci structure to remove.
  *
- * Returns:
- *     0       Success
- *     1       Failure
+ * Return pointer to removed mci structure, or NULL if device not found.
  */
-int edac_mc_del_mc(struct mem_ctl_info *mci)
+struct mem_ctl_info * edac_mc_del_mc(struct pci_dev *pdev)
 {
-       int rc = 1;
+       struct mem_ctl_info *mci;
 
-       debugf0("MC%d: %s()\n", mci->mc_idx, __func__);
-       edac_remove_sysfs_mci_device(mci);
+       debugf0("MC: %s()\n", __func__);
        down(&mem_ctls_mutex);
+
+       if ((mci = find_mci_by_pdev(pdev)) == NULL) {
+               up(&mem_ctls_mutex);
+               return NULL;
+       }
+
+       edac_remove_sysfs_mci_device(mci);
        del_mc_from_global_list(mci);
+       up(&mem_ctls_mutex);
        edac_printk(KERN_INFO, EDAC_MC,
                "Removed device %d for %s %s: PCI %s\n", mci->mc_idx,
                mci->mod_name, mci->ctl_name, pci_name(mci->pdev));
-       rc = 0;
-       up(&mem_ctls_mutex);
-
-       return rc;
+       return mci;
 }
 
 
@@ -2018,14 +2016,12 @@ static inline void clear_pci_parity_errors(void)
  */
 static inline void check_mc_devices (void)
 {
-       unsigned long flags;
        struct list_head *item;
        struct mem_ctl_info *mci;
 
        debugf3("%s()\n", __func__);
 
-       /* during poll, have interrupts off */
-       local_irq_save(flags);
+       down(&mem_ctls_mutex);
 
        list_for_each(item, &mc_devices) {
                mci = list_entry(item, struct mem_ctl_info, link);
@@ -2034,7 +2030,7 @@ static inline void check_mc_devices (void)
                        mci->edac_check(mci);
        }
 
-       local_irq_restore(flags);
+       up(&mem_ctls_mutex);
 }
 
 
index c9c1590db7219f6d297527ca9d1a0c1ede9421a3..2cec157aaebaf5472e786ccfd76402811127e8ae 100644 (file)
@@ -410,14 +410,11 @@ void edac_mc_dump_csrow(struct csrow_info *csrow);
 #endif                         /* CONFIG_EDAC_DEBUG */
 
 extern int edac_mc_add_mc(struct mem_ctl_info *mci);
-extern int edac_mc_del_mc(struct mem_ctl_info *mci);
+extern struct mem_ctl_info * edac_mc_del_mc(struct pci_dev *pdev);
 
 extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci,
                                           unsigned long page);
 
-extern struct mem_ctl_info *edac_mc_find_mci_by_pdev(struct pci_dev
-                                                         *pdev);
-
 extern void edac_mc_scrub_block(unsigned long page,
                                     unsigned long offset, u32 size);
 
index 942129df0212465559b4e87ed9c01a42df8fc3fd..688854260a0e72bde108a73717bbd39b0e4f9865 100644 (file)
@@ -237,9 +237,10 @@ static void __devexit i82860_remove_one(struct pci_dev *pdev)
 
        debugf0("%s()\n", __func__);
 
-       mci = edac_mc_find_mci_by_pdev(pdev);
-       if ((mci != NULL) && (edac_mc_del_mc(mci) == 0))
-               edac_mc_free(mci);
+       if ((mci = edac_mc_del_mc(pdev)) == NULL)
+               return;
+
+       edac_mc_free(mci);
 }
 
 static const struct pci_device_id i82860_pci_tbl[] __devinitdata = {
index 40ba2be6169af526f3b0900f083b31ddd84c280d..aad1900a46895c8043de69b5a404cc31f4ea293a 100644 (file)
@@ -452,7 +452,7 @@ static void __devexit i82875p_remove_one(struct pci_dev *pdev)
 
        debugf0("%s()\n", __func__);
 
-       if ((mci = edac_mc_find_mci_by_pdev(pdev)) == NULL)
+       if ((mci = edac_mc_del_mc(pdev)) == NULL)
                return;
 
        pvt = (struct i82875p_pvt *) mci->pvt_info;
@@ -467,9 +467,6 @@ static void __devexit i82875p_remove_one(struct pci_dev *pdev)
                pci_dev_put(pvt->ovrfl_pdev);
        }
 
-       if (edac_mc_del_mc(mci))
-               return;
-
        edac_mc_free(mci);
 }
 
index 787a7652c7ef94e0cbd390530015ede2dcf692cb..5966916d02bd087be402991e721c3a91ec774f66 100644 (file)
@@ -353,9 +353,10 @@ static void __devexit r82600_remove_one(struct pci_dev *pdev)
 
        debugf0("%s()\n", __func__);
 
-       if (((mci = edac_mc_find_mci_by_pdev(pdev)) != NULL) &&
-           !edac_mc_del_mc(mci))
-               edac_mc_free(mci);
+       if ((mci = edac_mc_del_mc(pdev)) == NULL)
+               return;
+
+       edac_mc_free(mci);
 }