tracing: Make exported ftrace_set_clr_event non-static
[linux-2.6-block.git] / mm / memremap.c
index 6ee03a816d67a889729e834b8c614675ac4cf94c..ed70c4e8e52a505f431fdeefaf209694a4b03093 100644 (file)
@@ -91,6 +91,12 @@ static void dev_pagemap_cleanup(struct dev_pagemap *pgmap)
                wait_for_completion(&pgmap->done);
                percpu_ref_exit(pgmap->ref);
        }
+       /*
+        * Undo the pgmap ref assignment for the internal case as the
+        * caller may re-enable the same pgmap.
+        */
+       if (pgmap->ref == &pgmap->internal_ref)
+               pgmap->ref = NULL;
 }
 
 static void devm_memremap_pages_release(void *data)
@@ -397,6 +403,30 @@ void __put_devmap_managed_page(struct page *page)
 
                mem_cgroup_uncharge(page);
 
+               /*
+                * When a device_private page is freed, the page->mapping field
+                * may still contain a (stale) mapping value. For example, the
+                * lower bits of page->mapping may still identify the page as
+                * an anonymous page. Ultimately, this entire field is just
+                * stale and wrong, and it will cause errors if not cleared.
+                * One example is:
+                *
+                *  migrate_vma_pages()
+                *    migrate_vma_insert_page()
+                *      page_add_new_anon_rmap()
+                *        __page_set_anon_rmap()
+                *          ...checks page->mapping, via PageAnon(page) call,
+                *            and incorrectly concludes that the page is an
+                *            anonymous page. Therefore, it incorrectly,
+                *            silently fails to set up the new anon rmap.
+                *
+                * For other types of ZONE_DEVICE pages, migration is either
+                * handled differently or not done at all, so there is no need
+                * to clear page->mapping.
+                */
+               if (is_device_private_page(page))
+                       page->mapping = NULL;
+
                page->pgmap->ops->page_free(page);
        } else if (!count)
                __put_page(page);