]> rtime.felk.cvut.cz Git - linux-imx.git/blobdiff - mm/memory_hotplug.c
memory-hotplug: suppress "Trying to free nonexistent resource <XXXXXXXXXXXXXXXX-YYYYY...
[linux-imx.git] / mm / memory_hotplug.c
index 6a5b90d0cfd7cbd61f4bc679bb4313e7a374ac0d..56b758ae57d2eeb2230bbcaf3f8e8d4538a15a9d 100644 (file)
@@ -106,6 +106,7 @@ static void get_page_bootmem(unsigned long info,  struct page *page,
 void __ref put_page_bootmem(struct page *page)
 {
        unsigned long type;
+       struct zone *zone;
 
        type = (unsigned long) page->lru.next;
        BUG_ON(type < MEMORY_HOTPLUG_MIN_BOOTMEM_TYPE ||
@@ -116,6 +117,12 @@ void __ref put_page_bootmem(struct page *page)
                set_page_private(page, 0);
                INIT_LIST_HEAD(&page->lru);
                __free_pages_bootmem(page, 0);
+
+               zone = page_zone(page);
+               zone_span_writelock(zone);
+               zone->present_pages++;
+               zone_span_writeunlock(zone);
+               totalram_pages++;
        }
 
 }
@@ -362,11 +369,11 @@ int __remove_pages(struct zone *zone, unsigned long phys_start_pfn,
        BUG_ON(phys_start_pfn & ~PAGE_SECTION_MASK);
        BUG_ON(nr_pages % PAGES_PER_SECTION);
 
+       release_mem_region(phys_start_pfn << PAGE_SHIFT, nr_pages * PAGE_SIZE);
+
        sections_to_remove = nr_pages / PAGES_PER_SECTION;
        for (i = 0; i < sections_to_remove; i++) {
                unsigned long pfn = phys_start_pfn + i*PAGES_PER_SECTION;
-               release_mem_region(pfn << PAGE_SHIFT,
-                                  PAGES_PER_SECTION << PAGE_SHIFT);
                ret = __remove_section(zone, __pfn_to_section(pfn));
                if (ret)
                        break;
@@ -756,13 +763,6 @@ static unsigned long scan_lru_pages(unsigned long start, unsigned long end)
        return 0;
 }
 
-static struct page *
-hotremove_migrate_alloc(struct page *page, unsigned long private, int **x)
-{
-       /* This should be improooooved!! */
-       return alloc_page(GFP_HIGHUSER_MOVABLE);
-}
-
 #define NR_OFFLINE_AT_ONCE_PAGES       (256)
 static int
 do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
@@ -813,8 +813,12 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
                        putback_lru_pages(&source);
                        goto out;
                }
-               /* this function returns # of failed pages */
-               ret = migrate_pages(&source, hotremove_migrate_alloc, 0,
+
+               /*
+                * alloc_migrate_target should be improooooved!!
+                * migrate_pages returns # of failed pages.
+                */
+               ret = migrate_pages(&source, alloc_migrate_target, 0,
                                                        true, MIGRATE_SYNC);
                if (ret)
                        putback_lru_pages(&source);
@@ -870,7 +874,7 @@ check_pages_isolated(unsigned long start_pfn, unsigned long end_pfn)
        return offlined;
 }
 
-static int __ref offline_pages(unsigned long start_pfn,
+static int __ref __offline_pages(unsigned long start_pfn,
                  unsigned long end_pfn, unsigned long timeout)
 {
        unsigned long pfn, nr_pages, expire;
@@ -970,8 +974,13 @@ repeat:
 
        init_per_zone_wmark_min();
 
-       if (!populated_zone(zone))
+       if (!populated_zone(zone)) {
                zone_pcp_reset(zone);
+               mutex_lock(&zonelists_mutex);
+               build_all_zonelists(NULL, NULL);
+               mutex_unlock(&zonelists_mutex);
+       } else
+               zone_pcp_update(zone);
 
        if (!node_present_pages(node)) {
                node_clear_state(node, N_HIGH_MEMORY);
@@ -998,15 +1007,55 @@ out:
        return ret;
 }
 
+int offline_pages(unsigned long start_pfn, unsigned long nr_pages)
+{
+       return __offline_pages(start_pfn, start_pfn + nr_pages, 120 * HZ);
+}
+
 int remove_memory(u64 start, u64 size)
 {
+       struct memory_block *mem = NULL;
+       struct mem_section *section;
        unsigned long start_pfn, end_pfn;
+       unsigned long pfn, section_nr;
+       int ret;
 
        start_pfn = PFN_DOWN(start);
        end_pfn = start_pfn + PFN_DOWN(size);
-       return offline_pages(start_pfn, end_pfn, 120 * HZ);
+
+       for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
+               section_nr = pfn_to_section_nr(pfn);
+               if (!present_section_nr(section_nr))
+                       continue;
+
+               section = __nr_to_section(section_nr);
+               /* same memblock? */
+               if (mem)
+                       if ((section_nr >= mem->start_section_nr) &&
+                           (section_nr <= mem->end_section_nr))
+                               continue;
+
+               mem = find_memory_block_hinted(section, mem);
+               if (!mem)
+                       continue;
+
+               ret = offline_memory_block(mem);
+               if (ret) {
+                       kobject_put(&mem->dev.kobj);
+                       return ret;
+               }
+       }
+
+       if (mem)
+               kobject_put(&mem->dev.kobj);
+
+       return 0;
 }
 #else
+int offline_pages(unsigned long start_pfn, unsigned long nr_pages)
+{
+       return -EINVAL;
+}
 int remove_memory(u64 start, u64 size)
 {
        return -EINVAL;