Merge tag '6.2-rc-smb3-client-fixes-part2' of git://git.samba.org/sfrench/cifs-2.6
[linux-block.git] / drivers / base / memory.c
index 9aa0da991cfb910955ece83be4be1970eced2749..fe98fb8d94e51c7749f3fa75f0f014ca804adfee 100644 (file)
@@ -175,6 +175,15 @@ int memory_notify(unsigned long val, void *v)
        return blocking_notifier_call_chain(&memory_chain, val, v);
 }
 
+#if defined(CONFIG_MEMORY_FAILURE) && defined(CONFIG_MEMORY_HOTPLUG)
+static unsigned long memblk_nr_poison(struct memory_block *mem);
+#else
+static inline unsigned long memblk_nr_poison(struct memory_block *mem)
+{
+       return 0;
+}
+#endif
+
 static int memory_block_online(struct memory_block *mem)
 {
        unsigned long start_pfn = section_nr_to_pfn(mem->start_section_nr);
@@ -183,6 +192,9 @@ static int memory_block_online(struct memory_block *mem)
        struct zone *zone;
        int ret;
 
+       if (memblk_nr_poison(mem))
+               return -EHWPOISON;
+
        zone = zone_for_pfn_range(mem->online_type, mem->nid, mem->group,
                                  start_pfn, nr_pages);
 
@@ -864,6 +876,7 @@ void remove_memory_block_devices(unsigned long start, unsigned long size)
                mem = find_memory_block_by_id(block_id);
                if (WARN_ON_ONCE(!mem))
                        continue;
+               num_poisoned_pages_sub(-1UL, memblk_nr_poison(mem));
                unregister_memory_block_under_nodes(mem);
                remove_memory_block(mem);
        }
@@ -1164,3 +1177,28 @@ int walk_dynamic_memory_groups(int nid, walk_memory_groups_func_t func,
        }
        return ret;
 }
+
+#if defined(CONFIG_MEMORY_FAILURE) && defined(CONFIG_MEMORY_HOTPLUG)
+void memblk_nr_poison_inc(unsigned long pfn)
+{
+       const unsigned long block_id = pfn_to_block_id(pfn);
+       struct memory_block *mem = find_memory_block_by_id(block_id);
+
+       if (mem)
+               atomic_long_inc(&mem->nr_hwpoison);
+}
+
+void memblk_nr_poison_sub(unsigned long pfn, long i)
+{
+       const unsigned long block_id = pfn_to_block_id(pfn);
+       struct memory_block *mem = find_memory_block_by_id(block_id);
+
+       if (mem)
+               atomic_long_sub(i, &mem->nr_hwpoison);
+}
+
+static unsigned long memblk_nr_poison(struct memory_block *mem)
+{
+       return atomic_long_read(&mem->nr_hwpoison);
+}
+#endif