scsi: fdomain: Resurrect driver - Core
[linux-2.6-microblaze.git] / mm / memory_hotplug.c
index a279671..328878b 100644 (file)
@@ -39,6 +39,7 @@
 #include <asm/tlbflush.h>
 
 #include "internal.h"
+#include "shuffle.h"
 
 /*
  * online_page_callback contains pointer to current page onlining function.
@@ -273,12 +274,12 @@ static int __meminit __add_section(int nid, unsigned long phys_start_pfn,
  * add the new pages.
  */
 int __ref __add_pages(int nid, unsigned long phys_start_pfn,
-               unsigned long nr_pages, struct vmem_altmap *altmap,
-               bool want_memblock)
+               unsigned long nr_pages, struct mhp_restrictions *restrictions)
 {
        unsigned long i;
        int err = 0;
        int start_sec, end_sec;
+       struct vmem_altmap *altmap = restrictions->altmap;
 
        /* during initialize mem_map, align hot-added range to section */
        start_sec = pfn_to_section_nr(phys_start_pfn);
@@ -299,7 +300,7 @@ int __ref __add_pages(int nid, unsigned long phys_start_pfn,
 
        for (i = start_sec; i <= end_sec; i++) {
                err = __add_section(nid, section_nr_to_pfn(i), altmap,
-                               want_memblock);
+                               restrictions->flags & MHP_MEMBLOCK_API);
 
                /*
                 * EEXIST is finally dealt with by ioresource collision
@@ -516,26 +517,23 @@ static void __remove_zone(struct zone *zone, unsigned long start_pfn)
        pgdat_resize_unlock(zone->zone_pgdat, &flags);
 }
 
-static int __remove_section(struct zone *zone, struct mem_section *ms,
-               unsigned long map_offset, struct vmem_altmap *altmap)
+static void __remove_section(struct zone *zone, struct mem_section *ms,
+                            unsigned long map_offset,
+                            struct vmem_altmap *altmap)
 {
        unsigned long start_pfn;
        int scn_nr;
-       int ret = -EINVAL;
 
-       if (!valid_section(ms))
-               return ret;
+       if (WARN_ON_ONCE(!valid_section(ms)))
+               return;
 
-       ret = unregister_memory_section(ms);
-       if (ret)
-               return ret;
+       unregister_memory_section(ms);
 
        scn_nr = __section_nr(ms);
        start_pfn = section_nr_to_pfn((unsigned long)scn_nr);
        __remove_zone(zone, start_pfn);
 
        sparse_remove_one_section(zone, ms, map_offset, altmap);
-       return 0;
 }
 
 /**
@@ -550,31 +548,17 @@ static int __remove_section(struct zone *zone, struct mem_section *ms,
  * sure that pages are marked reserved and zones are adjust properly by
  * calling offline_pages().
  */
-int __remove_pages(struct zone *zone, unsigned long phys_start_pfn,
-                unsigned long nr_pages, struct vmem_altmap *altmap)
+void __remove_pages(struct zone *zone, unsigned long phys_start_pfn,
+                   unsigned long nr_pages, struct vmem_altmap *altmap)
 {
        unsigned long i;
        unsigned long map_offset = 0;
-       int sections_to_remove, ret = 0;
+       int sections_to_remove;
 
        /* In the ZONE_DEVICE case device driver owns the memory region */
        if (is_dev_zone(zone)) {
                if (altmap)
                        map_offset = vmem_altmap_offset(altmap);
-       } else {
-               resource_size_t start, size;
-
-               start = phys_start_pfn << PAGE_SHIFT;
-               size = nr_pages * PAGE_SIZE;
-
-               ret = release_mem_region_adjustable(&iomem_resource, start,
-                                       size);
-               if (ret) {
-                       resource_size_t endres = start + size - 1;
-
-                       pr_warn("Unable to release resource <%pa-%pa> (%d)\n",
-                                       &start, &endres, ret);
-               }
        }
 
        clear_zone_contiguous(zone);
@@ -590,16 +574,12 @@ int __remove_pages(struct zone *zone, unsigned long phys_start_pfn,
                unsigned long pfn = phys_start_pfn + i*PAGES_PER_SECTION;
 
                cond_resched();
-               ret = __remove_section(zone, __pfn_to_section(pfn), map_offset,
-                               altmap);
+               __remove_section(zone, __pfn_to_section(pfn), map_offset,
+                                altmap);
                map_offset = 0;
-               if (ret)
-                       break;
        }
 
        set_zone_contiguous(zone);
-
-       return ret;
 }
 #endif /* CONFIG_MEMORY_HOTREMOVE */
 
@@ -912,6 +892,8 @@ int __ref online_pages(unsigned long pfn, unsigned long nr_pages, int online_typ
        zone->zone_pgdat->node_present_pages += onlined_pages;
        pgdat_resize_unlock(zone->zone_pgdat, &flags);
 
+       shuffle_zone(zone);
+
        if (onlined_pages) {
                node_states_set_node(nid, &arg);
                if (need_zonelists_rebuild)
@@ -1097,6 +1079,9 @@ static int online_memory_block(struct memory_block *mem, void *arg)
  */
 int __ref add_memory_resource(int nid, struct resource *res)
 {
+       struct mhp_restrictions restrictions = {
+               .flags = MHP_MEMBLOCK_API,
+       };
        u64 start, size;
        bool new_node = false;
        int ret;
@@ -1124,7 +1109,7 @@ int __ref add_memory_resource(int nid, struct resource *res)
        new_node = ret;
 
        /* call arch's memory hotadd */
-       ret = arch_add_memory(nid, start, size, NULL, true);
+       ret = arch_add_memory(nid, start, size, &restrictions);
        if (ret < 0)
                goto error;
 
@@ -1449,15 +1434,10 @@ static int
 offline_isolated_pages_cb(unsigned long start, unsigned long nr_pages,
                        void *data)
 {
-       __offline_isolated_pages(start, start + nr_pages);
-       return 0;
-}
+       unsigned long *offlined_pages = (unsigned long *)data;
 
-static void
-offline_isolated_pages(unsigned long start_pfn, unsigned long end_pfn)
-{
-       walk_system_ram_range(start_pfn, end_pfn - start_pfn, NULL,
-                               offline_isolated_pages_cb);
+       *offlined_pages += __offline_isolated_pages(start, start + nr_pages);
+       return 0;
 }
 
 /*
@@ -1467,26 +1447,7 @@ static int
 check_pages_isolated_cb(unsigned long start_pfn, unsigned long nr_pages,
                        void *data)
 {
-       int ret;
-       long offlined = *(long *)data;
-       ret = test_pages_isolated(start_pfn, start_pfn + nr_pages, true);
-       offlined = nr_pages;
-       if (!ret)
-               *(long *)data += offlined;
-       return ret;
-}
-
-static long
-check_pages_isolated(unsigned long start_pfn, unsigned long end_pfn)
-{
-       long offlined = 0;
-       int ret;
-
-       ret = walk_system_ram_range(start_pfn, end_pfn - start_pfn, &offlined,
-                       check_pages_isolated_cb);
-       if (ret < 0)
-               offlined = (long)ret;
-       return offlined;
+       return test_pages_isolated(start_pfn, start_pfn + nr_pages, true);
 }
 
 static int __init cmdline_parse_movable_node(char *p)
@@ -1571,7 +1532,7 @@ static int __ref __offline_pages(unsigned long start_pfn,
                  unsigned long end_pfn)
 {
        unsigned long pfn, nr_pages;
-       long offlined_pages;
+       unsigned long offlined_pages = 0;
        int ret, node, nr_isolate_pageblock;
        unsigned long flags;
        unsigned long valid_start, valid_end;
@@ -1647,14 +1608,15 @@ static int __ref __offline_pages(unsigned long start_pfn,
                        goto failed_removal_isolated;
                }
                /* check again */
-               offlined_pages = check_pages_isolated(start_pfn, end_pfn);
-       } while (offlined_pages < 0);
+               ret = walk_system_ram_range(start_pfn, end_pfn - start_pfn,
+                                           NULL, check_pages_isolated_cb);
+       } while (ret);
 
-       pr_info("Offlined Pages %ld\n", offlined_pages);
        /* Ok, all of our target is isolated.
           We cannot do rollback at this point. */
-       offline_isolated_pages(start_pfn, end_pfn);
-
+       walk_system_ram_range(start_pfn, end_pfn - start_pfn,
+                             &offlined_pages, offline_isolated_pages_cb);
+       pr_info("Offlined Pages %ld\n", offlined_pages);
        /*
         * Onlining will reset pagetype flags and makes migrate type
         * MOVABLE, so just need to decrease the number of isolated
@@ -1838,6 +1800,26 @@ void try_offline_node(int nid)
 }
 EXPORT_SYMBOL(try_offline_node);
 
+static void __release_memory_resource(resource_size_t start,
+                                     resource_size_t size)
+{
+       int ret;
+
+       /*
+        * When removing memory in the same granularity as it was added,
+        * this function never fails. It might only fail if resources
+        * have to be adjusted or split. We'll ignore the error, as
+        * removing of memory cannot fail.
+        */
+       ret = release_mem_region_adjustable(&iomem_resource, start, size);
+       if (ret) {
+               resource_size_t endres = start + size - 1;
+
+               pr_warn("Unable to release resource <%pa-%pa> (%d)\n",
+                       &start, &endres, ret);
+       }
+}
+
 /**
  * remove_memory
  * @nid: the node ID
@@ -1872,6 +1854,7 @@ void __ref __remove_memory(int nid, u64 start, u64 size)
        memblock_remove(start, size);
 
        arch_remove_memory(nid, start, size, NULL);
+       __release_memory_resource(start, size);
 
        try_offline_node(nid);