cma: fix calculation of aligned offset
[linux-2.6-microblaze.git] / mm / memory_hotplug.c
index f79aac7..7cd4377 100644 (file)
@@ -580,11 +580,8 @@ static void __remove_zone(struct zone *zone, unsigned long start_pfn)
 {
        struct pglist_data *pgdat = zone->zone_pgdat;
        int nr_pages = PAGES_PER_SECTION;
-       int zone_type;
        unsigned long flags;
 
-       zone_type = zone - pgdat->node_zones;
-
        pgdat_resize_lock(zone->zone_pgdat, &flags);
        shrink_zone_span(zone, start_pfn, start_pfn + nr_pages);
        shrink_pgdat_span(pgdat, start_pfn, start_pfn + nr_pages);
@@ -934,6 +931,19 @@ struct zone *default_zone_for_pfn(int nid, unsigned long start_pfn,
        return &pgdat->node_zones[ZONE_NORMAL];
 }
 
+static inline bool movable_pfn_range(int nid, struct zone *default_zone,
+               unsigned long start_pfn, unsigned long nr_pages)
+{
+       if (!allow_online_pfn_range(nid, start_pfn, nr_pages,
+                               MMOP_ONLINE_KERNEL))
+               return true;
+
+       if (!movable_node_is_enabled())
+               return false;
+
+       return !zone_intersects(default_zone, start_pfn, nr_pages);
+}
+
 /*
  * Associates the given pfn range with the given node and the zone appropriate
  * for the given online type.
@@ -949,10 +959,10 @@ static struct zone * __meminit move_pfn_range(int online_type, int nid,
                /*
                 * MMOP_ONLINE_KEEP defaults to MMOP_ONLINE_KERNEL but use
                 * movable zone if that is not possible (e.g. we are within
-                * or past the existing movable zone)
+                * or past the existing movable zone). movable_node overrides
+                * this default and defaults to movable zone
                 */
-               if (!allow_online_pfn_range(nid, start_pfn, nr_pages,
-                                       MMOP_ONLINE_KERNEL))
+               if (movable_pfn_range(nid, zone, start_pfn, nr_pages))
                        zone = movable_zone;
        } else if (online_type == MMOP_ONLINE_MOVABLE) {
                zone = &pgdat->node_zones[ZONE_MOVABLE];
@@ -1268,7 +1278,7 @@ register_fail:
 
 error:
        /* rollback pgdat allocation and others */
-       if (new_pgdat)
+       if (new_pgdat && pgdat)
                rollback_node_hotadd(nid, pgdat);
        memblock_remove(start, size);
 
@@ -1420,32 +1430,19 @@ static unsigned long scan_movable_pages(unsigned long start, unsigned long end)
 static struct page *new_node_page(struct page *page, unsigned long private,
                int **result)
 {
-       gfp_t gfp_mask = GFP_USER | __GFP_MOVABLE;
        int nid = page_to_nid(page);
        nodemask_t nmask = node_states[N_MEMORY];
-       struct page *new_page = NULL;
 
        /*
-        * TODO: allocate a destination hugepage from a nearest neighbor node,
-        * accordance with memory policy of the user process if possible. For
-        * now as a simple work-around, we use the next node for destination.
+        * try to allocate from a different node but reuse this node if there
+        * are no other online nodes to be used (e.g. we are offlining a part
+        * of the only existing node)
         */
-       if (PageHuge(page))
-               return alloc_huge_page_node(page_hstate(compound_head(page)),
-                                       next_node_in(nid, nmask));
-
        node_clear(nid, nmask);
+       if (nodes_empty(nmask))
+               node_set(nid, nmask);
 
-       if (PageHighMem(page)
-           || (zone_idx(page_zone(page)) == ZONE_MOVABLE))
-               gfp_mask |= __GFP_HIGHMEM;
-
-       if (!nodes_empty(nmask))
-               new_page = __alloc_pages_nodemask(gfp_mask, 0, nid, &nmask);
-       if (!new_page)
-               new_page = __alloc_pages(gfp_mask, 0, nid);
-
-       return new_page;
+       return new_page_nodemask(page, nid, &nmask);
 }
 
 #define NR_OFFLINE_AT_ONCE_PAGES       (256)