]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - mm/memory_hotplug.c
Merge tag 'media/v4.11-3' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[mirror_ubuntu-artful-kernel.git] / mm / memory_hotplug.c
index b8c11e063ff0746316fb792f4fe1dde0094cb828..6fa7208bcd564ec8fb6bcf25e206aef9bd724ecb 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <linux/stddef.h>
 #include <linux/mm.h>
+#include <linux/sched/signal.h>
 #include <linux/swap.h>
 #include <linux/interrupt.h>
 #include <linux/pagemap.h>
@@ -124,8 +125,13 @@ void put_online_mems(void)
 
 }
 
+/* Serializes write accesses to mem_hotplug.active_writer. */
+static DEFINE_MUTEX(memory_add_remove_lock);
+
 void mem_hotplug_begin(void)
 {
+       mutex_lock(&memory_add_remove_lock);
+
        mem_hotplug.active_writer = current;
 
        memhp_lock_acquire();
@@ -144,6 +150,7 @@ void mem_hotplug_done(void)
        mem_hotplug.active_writer = NULL;
        mutex_unlock(&mem_hotplug.lock);
        memhp_lock_release();
+       mutex_unlock(&memory_add_remove_lock);
 }
 
 /* add this memory to iomem resource */
@@ -179,7 +186,7 @@ static void release_memory_resource(struct resource *res)
 void get_page_bootmem(unsigned long info,  struct page *page,
                      unsigned long type)
 {
-       page->lru.next = (struct list_head *) type;
+       page->freelist = (void *)type;
        SetPagePrivate(page);
        set_page_private(page, info);
        page_ref_inc(page);
@@ -189,11 +196,12 @@ void put_page_bootmem(struct page *page)
 {
        unsigned long type;
 
-       type = (unsigned long) page->lru.next;
+       type = (unsigned long) page->freelist;
        BUG_ON(type < MEMORY_HOTPLUG_MIN_BOOTMEM_TYPE ||
               type > MEMORY_HOTPLUG_MAX_BOOTMEM_TYPE);
 
        if (page_ref_dec_return(page) == 1) {
+               page->freelist = NULL;
                ClearPagePrivate(page);
                set_page_private(page, 0);
                INIT_LIST_HEAD(&page->lru);
@@ -861,7 +869,6 @@ int __remove_pages(struct zone *zone, unsigned long phys_start_pfn,
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(__remove_pages);
 #endif /* CONFIG_MEMORY_HOTREMOVE */
 
 int set_online_page_callback(online_page_callback_t callback)
@@ -1335,7 +1342,7 @@ int zone_for_memory(int nid, u64 start, u64 size, int zone_default,
 
 static int online_memory_block(struct memory_block *mem, void *arg)
 {
-       return memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE);
+       return device_online(&mem->dev);
 }
 
 /* we are OK calling __meminit stuff here - we have CONFIG_MEMORY_HOTPLUG */
@@ -1507,7 +1514,7 @@ int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn,
                        while ((i < MAX_ORDER_NR_PAGES) &&
                                !pfn_valid_within(pfn + i))
                                i++;
-                       if (i == MAX_ORDER_NR_PAGES)
+                       if (i == MAX_ORDER_NR_PAGES || pfn + i >= end_pfn)
                                continue;
                        page = pfn_to_page(pfn + i);
                        if (zone && page_zone(page) != zone)
@@ -1521,7 +1528,7 @@ int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn,
 
        if (zone) {
                *valid_start = start;
-               *valid_end = end;
+               *valid_end = min(end, end_pfn);
                return 1;
        } else {
                return 0;
@@ -1529,10 +1536,10 @@ int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn,
 }
 
 /*
- * Scan pfn range [start,end) to find movable/migratable pages (LRU pages
- * and hugepages). We scan pfn because it's much easier than scanning over
- * linked list. This function returns the pfn of the first found movable
- * page if it's found, otherwise 0.
+ * Scan pfn range [start,end) to find movable/migratable pages (LRU pages,
+ * non-lru movable pages and hugepages). We scan pfn because it's much
+ * easier than scanning over linked list. This function returns the pfn
+ * of the first found movable page if it's found, otherwise 0.
  */
 static unsigned long scan_movable_pages(unsigned long start, unsigned long end)
 {
@@ -1543,6 +1550,8 @@ static unsigned long scan_movable_pages(unsigned long start, unsigned long end)
                        page = pfn_to_page(pfn);
                        if (PageLRU(page))
                                return pfn;
+                       if (__PageMovable(page))
+                               return pfn;
                        if (PageHuge(page)) {
                                if (page_huge_active(page))
                                        return pfn;
@@ -1619,21 +1628,25 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
                if (!get_page_unless_zero(page))
                        continue;
                /*
-                * We can skip free pages. And we can only deal with pages on
-                * LRU.
+                * We can skip free pages. And we can deal with pages on
+                * LRU and non-lru movable pages.
                 */
-               ret = isolate_lru_page(page);
+               if (PageLRU(page))
+                       ret = isolate_lru_page(page);
+               else
+                       ret = isolate_movable_page(page, ISOLATE_UNEVICTABLE);
                if (!ret) { /* Success */
                        put_page(page);
                        list_add_tail(&page->lru, &source);
                        move_pages--;
-                       inc_node_page_state(page, NR_ISOLATED_ANON +
-                                           page_is_file_cache(page));
+                       if (!__PageMovable(page))
+                               inc_node_page_state(page, NR_ISOLATED_ANON +
+                                                   page_is_file_cache(page));
 
                } else {
 #ifdef CONFIG_DEBUG_VM
-                       pr_alert("removing pfn %lx from LRU failed\n", pfn);
-                       dump_page(page, "failed to remove from LRU");
+                       pr_alert("failed to isolate pfn %lx\n", pfn);
+                       dump_page(page, "isolation failed");
 #endif
                        put_page(page);
                        /* Because we don't have big zone->lock. we should