Merge branches 'acpi-ec' and 'acpi-x86'
[linux-2.6-microblaze.git] / mm / migrate.c
index b109287..7ded070 100644 (file)
@@ -1282,6 +1282,7 @@ static int unmap_and_move_huge_page(new_page_t get_new_page,
        int page_was_mapped = 0;
        struct page *new_hpage;
        struct anon_vma *anon_vma = NULL;
+       struct address_space *mapping = NULL;
 
        /*
         * Migratability of hugepages depends on architectures and their size.
@@ -1329,18 +1330,36 @@ static int unmap_and_move_huge_page(new_page_t get_new_page,
                goto put_anon;
 
        if (page_mapped(hpage)) {
+               /*
+                * try_to_unmap could potentially call huge_pmd_unshare.
+                * Because of this, take semaphore in write mode here and
+                * set TTU_RMAP_LOCKED to let lower levels know we have
+                * taken the lock.
+                */
+               mapping = hugetlb_page_mapping_lock_write(hpage);
+               if (unlikely(!mapping))
+                       goto unlock_put_anon;
+
                try_to_unmap(hpage,
-                       TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS);
+                       TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS|
+                       TTU_RMAP_LOCKED);
                page_was_mapped = 1;
+               /*
+                * Leave mapping locked until after subsequent call to
+                * remove_migration_ptes()
+                */
        }
 
        if (!page_mapped(hpage))
                rc = move_to_new_page(new_hpage, hpage, mode);
 
-       if (page_was_mapped)
+       if (page_was_mapped) {
                remove_migration_ptes(hpage,
-                       rc == MIGRATEPAGE_SUCCESS ? new_hpage : hpage, false);
+                       rc == MIGRATEPAGE_SUCCESS ? new_hpage : hpage, true);
+               i_mmap_unlock_write(mapping);
+       }
 
+unlock_put_anon:
        unlock_page(new_hpage);
 
 put_anon:
@@ -2241,7 +2260,7 @@ again:
        arch_enter_lazy_mmu_mode();
 
        for (; addr < end; addr += PAGE_SIZE, ptep++) {
-               unsigned long mpfn, pfn;
+               unsigned long mpfn = 0, pfn;
                struct page *page;
                swp_entry_t entry;
                pte_t pte;
@@ -2255,8 +2274,6 @@ again:
                }
 
                if (!pte_present(pte)) {
-                       mpfn = 0;
-
                        /*
                         * Only care about unaddressable device page special
                         * page table entry. Other special swap entries are not
@@ -2267,11 +2284,16 @@ again:
                                goto next;
 
                        page = device_private_entry_to_page(entry);
+                       if (page->pgmap->owner != migrate->src_owner)
+                               goto next;
+
                        mpfn = migrate_pfn(page_to_pfn(page)) |
                                        MIGRATE_PFN_MIGRATE;
                        if (is_write_device_private_entry(entry))
                                mpfn |= MIGRATE_PFN_WRITE;
                } else {
+                       if (migrate->src_owner)
+                               goto next;
                        pfn = pte_pfn(pte);
                        if (is_zero_pfn(pfn)) {
                                mpfn = MIGRATE_PFN_MIGRATE;