EDAC, mc: Fix locking around mc_devices list
authorBorislav Petkov <bp@suse.de>
Mon, 14 Nov 2016 12:26:11 +0000 (13:26 +0100)
committerBorislav Petkov <bp@suse.de>
Mon, 14 Nov 2016 12:26:11 +0000 (13:26 +0100)
When accessing the mc_devices list of memory controller descriptors, we
need to hold mem_ctls_mutex. This was not always the case, fix that.

Make all external callers call a version which grabs the mutex since the
last is local to edac_mc.c.

Reported-by: Yazen Ghannam <yazen.ghannam@amd.com>
Signed-off-by: Borislav Petkov <bp@suse.de>
drivers/edac/edac_mc.c

index c3ee3ad98a63834e055b0218465d3033ff127a1c..d2ea9c4f1824280177fc52ad99d9010e69666515 100644 (file)
@@ -482,15 +482,8 @@ void edac_mc_free(struct mem_ctl_info *mci)
 }
 EXPORT_SYMBOL_GPL(edac_mc_free);
 
-
-/**
- * find_mci_by_dev
- *
- *     scan list of controllers looking for the one that manages
- *     the 'dev' device
- * @dev: pointer to a struct device related with the MCI
- */
-struct mem_ctl_info *find_mci_by_dev(struct device *dev)
+/* Caller must hold mem_ctls_mutex */
+static struct mem_ctl_info *__find_mci_by_dev(struct device *dev)
 {
        struct mem_ctl_info *mci;
        struct list_head *item;
@@ -506,6 +499,24 @@ struct mem_ctl_info *find_mci_by_dev(struct device *dev)
 
        return NULL;
 }
+
+/**
+ * find_mci_by_dev
+ *
+ *     scan list of controllers looking for the one that manages
+ *     the 'dev' device
+ * @dev: pointer to a struct device related with the MCI
+ */
+struct mem_ctl_info *find_mci_by_dev(struct device *dev)
+{
+       struct mem_ctl_info *ret;
+
+       mutex_lock(&mem_ctls_mutex);
+       ret = __find_mci_by_dev(dev);
+       mutex_unlock(&mem_ctls_mutex);
+
+       return ret;
+}
 EXPORT_SYMBOL_GPL(find_mci_by_dev);
 
 /*
@@ -588,7 +599,7 @@ static int add_mc_to_global_list(struct mem_ctl_info *mci)
 
        insert_before = &mc_devices;
 
-       p = find_mci_by_dev(mci->pdev);
+       p = __find_mci_by_dev(mci->pdev);
        if (unlikely(p != NULL))
                goto fail0;
 
@@ -640,26 +651,28 @@ static int del_mc_from_global_list(struct mem_ctl_info *mci)
  *
  * If found, return a pointer to the structure.
  * Else return NULL.
- *
- * Caller must hold mem_ctls_mutex.
  */
 struct mem_ctl_info *edac_mc_find(int idx)
 {
+       struct mem_ctl_info *mci = NULL;
        struct list_head *item;
-       struct mem_ctl_info *mci;
+
+       mutex_lock(&mem_ctls_mutex);
 
        list_for_each(item, &mc_devices) {
                mci = list_entry(item, struct mem_ctl_info, link);
 
                if (mci->mc_idx >= idx) {
-                       if (mci->mc_idx == idx)
-                               return mci;
-
+                       if (mci->mc_idx == idx) {
+                               goto unlock;
+                       }
                        break;
                }
        }
 
-       return NULL;
+unlock:
+       mutex_unlock(&mem_ctls_mutex);
+       return mci;
 }
 EXPORT_SYMBOL(edac_mc_find);
 
@@ -779,7 +792,7 @@ struct mem_ctl_info *edac_mc_del_mc(struct device *dev)
        mutex_lock(&mem_ctls_mutex);
 
        /* find the requested mci struct in the global list */
-       mci = find_mci_by_dev(dev);
+       mci = __find_mci_by_dev(dev);
        if (mci == NULL) {
                mutex_unlock(&mem_ctls_mutex);
                return NULL;