Merge tag 'drm-fixes-2020-05-08' of git://anongit.freedesktop.org/drm/drm
[linux-2.6-microblaze.git] / mm / page_alloc.c
index e5f76da..13cc653 100644 (file)
@@ -74,6 +74,7 @@
 #include <asm/div64.h>
 #include "internal.h"
 #include "shuffle.h"
+#include "page_reporting.h"
 
 /* prevent >1 _updater_ of zone percpu pageset ->high and ->batch fields */
 static DEFINE_MUTEX(pcp_batch_high_lock);
@@ -102,8 +103,8 @@ struct pcpu_drain {
        struct zone *zone;
        struct work_struct work;
 };
-DEFINE_MUTEX(pcpu_drain_mutex);
-DEFINE_PER_CPU(struct pcpu_drain, pcpu_drain);
+static DEFINE_MUTEX(pcpu_drain_mutex);
+static DEFINE_PER_CPU(struct pcpu_drain, pcpu_drain);
 
 #ifdef CONFIG_GCC_PLUGIN_LATENT_ENTROPY
 volatile unsigned long latent_entropy __latent_entropy;
@@ -864,6 +865,78 @@ compaction_capture(struct capture_control *capc, struct page *page,
 }
 #endif /* CONFIG_COMPACTION */
 
+/* Used for pages not on another list */
+static inline void add_to_free_list(struct page *page, struct zone *zone,
+                                   unsigned int order, int migratetype)
+{
+       struct free_area *area = &zone->free_area[order];
+
+       list_add(&page->lru, &area->free_list[migratetype]);
+       area->nr_free++;
+}
+
+/* Used for pages not on another list */
+static inline void add_to_free_list_tail(struct page *page, struct zone *zone,
+                                        unsigned int order, int migratetype)
+{
+       struct free_area *area = &zone->free_area[order];
+
+       list_add_tail(&page->lru, &area->free_list[migratetype]);
+       area->nr_free++;
+}
+
+/* Used for pages which are on another list */
+static inline void move_to_free_list(struct page *page, struct zone *zone,
+                                    unsigned int order, int migratetype)
+{
+       struct free_area *area = &zone->free_area[order];
+
+       list_move(&page->lru, &area->free_list[migratetype]);
+}
+
+static inline void del_page_from_free_list(struct page *page, struct zone *zone,
+                                          unsigned int order)
+{
+       /* clear reported state and update reported page count */
+       if (page_reported(page))
+               __ClearPageReported(page);
+
+       list_del(&page->lru);
+       __ClearPageBuddy(page);
+       set_page_private(page, 0);
+       zone->free_area[order].nr_free--;
+}
+
+/*
+ * If this is not the largest possible page, check if the buddy
+ * of the next-highest order is free. If it is, it's possible
+ * that pages are being freed that will coalesce soon. In case,
+ * that is happening, add the free page to the tail of the list
+ * so it's less likely to be used soon and more likely to be merged
+ * as a higher order page
+ */
+static inline bool
+buddy_merge_likely(unsigned long pfn, unsigned long buddy_pfn,
+                  struct page *page, unsigned int order)
+{
+       struct page *higher_page, *higher_buddy;
+       unsigned long combined_pfn;
+
+       if (order >= MAX_ORDER - 2)
+               return false;
+
+       if (!pfn_valid_within(buddy_pfn))
+               return false;
+
+       combined_pfn = buddy_pfn & pfn;
+       higher_page = page + (combined_pfn - pfn);
+       buddy_pfn = __find_buddy_pfn(combined_pfn, order + 1);
+       higher_buddy = higher_page + (buddy_pfn - combined_pfn);
+
+       return pfn_valid_within(buddy_pfn) &&
+              page_is_buddy(higher_page, higher_buddy, order + 1);
+}
+
 /*
  * Freeing function for a buddy system allocator.
  *
@@ -891,13 +964,14 @@ compaction_capture(struct capture_control *capc, struct page *page,
 static inline void __free_one_page(struct page *page,
                unsigned long pfn,
                struct zone *zone, unsigned int order,
-               int migratetype)
+               int migratetype, bool report)
 {
-       unsigned long combined_pfn;
+       struct capture_control *capc = task_capc(zone);
        unsigned long uninitialized_var(buddy_pfn);
-       struct page *buddy;
+       unsigned long combined_pfn;
        unsigned int max_order;
-       struct capture_control *capc = task_capc(zone);
+       struct page *buddy;
+       bool to_tail;
 
        max_order = min_t(unsigned int, MAX_ORDER, pageblock_order + 1);
 
@@ -932,7 +1006,7 @@ continue_merging:
                if (page_is_guard(buddy))
                        clear_page_guard(zone, buddy, order, migratetype);
                else
-                       del_page_from_free_area(buddy, &zone->free_area[order]);
+                       del_page_from_free_list(buddy, zone, order);
                combined_pfn = buddy_pfn & pfn;
                page = page + (combined_pfn - pfn);
                pfn = combined_pfn;
@@ -966,35 +1040,19 @@ continue_merging:
 done_merging:
        set_page_order(page, order);
 
-       /*
-        * If this is not the largest possible page, check if the buddy
-        * of the next-highest order is free. If it is, it's possible
-        * that pages are being freed that will coalesce soon. In case,
-        * that is happening, add the free page to the tail of the list
-        * so it's less likely to be used soon and more likely to be merged
-        * as a higher order page
-        */
-       if ((order < MAX_ORDER-2) && pfn_valid_within(buddy_pfn)
-                       && !is_shuffle_order(order)) {
-               struct page *higher_page, *higher_buddy;
-               combined_pfn = buddy_pfn & pfn;
-               higher_page = page + (combined_pfn - pfn);
-               buddy_pfn = __find_buddy_pfn(combined_pfn, order + 1);
-               higher_buddy = higher_page + (buddy_pfn - combined_pfn);
-               if (pfn_valid_within(buddy_pfn) &&
-                   page_is_buddy(higher_page, higher_buddy, order + 1)) {
-                       add_to_free_area_tail(page, &zone->free_area[order],
-                                             migratetype);
-                       return;
-               }
-       }
-
        if (is_shuffle_order(order))
-               add_to_free_area_random(page, &zone->free_area[order],
-                               migratetype);
+               to_tail = shuffle_pick_tail();
+       else
+               to_tail = buddy_merge_likely(pfn, buddy_pfn, page, order);
+
+       if (to_tail)
+               add_to_free_list_tail(page, zone, order, migratetype);
        else
-               add_to_free_area(page, &zone->free_area[order], migratetype);
+               add_to_free_list(page, zone, order, migratetype);
 
+       /* Notify page reporting subsystem of freed page */
+       if (report)
+               page_reporting_notify_free(order);
 }
 
 /*
@@ -1311,7 +1369,7 @@ static void free_pcppages_bulk(struct zone *zone, int count,
                if (unlikely(isolated_pageblocks))
                        mt = get_pageblock_migratetype(page);
 
-               __free_one_page(page, page_to_pfn(page), zone, 0, mt);
+               __free_one_page(page, page_to_pfn(page), zone, 0, mt, true);
                trace_mm_page_pcpu_drain(page, 0, mt);
        }
        spin_unlock(&zone->lock);
@@ -1327,7 +1385,7 @@ static void free_one_page(struct zone *zone,
                is_migrate_isolate(migratetype))) {
                migratetype = get_pfnblock_migratetype(page, pfn);
        }
-       __free_one_page(page, pfn, zone, order, migratetype);
+       __free_one_page(page, pfn, zone, order, migratetype, true);
        spin_unlock(&zone->lock);
 }
 
@@ -1549,6 +1607,7 @@ void set_zone_contiguous(struct zone *zone)
                if (!__pageblock_pfn_to_page(block_start_pfn,
                                             block_end_pfn, zone))
                        return;
+               cond_resched();
        }
 
        /* We confirm that there is no hole */
@@ -2008,13 +2067,11 @@ void __init init_cma_reserved_pageblock(struct page *page)
  * -- nyc
  */
 static inline void expand(struct zone *zone, struct page *page,
-       int low, int high, struct free_area *area,
-       int migratetype)
+       int low, int high, int migratetype)
 {
        unsigned long size = 1 << high;
 
        while (high > low) {
-               area--;
                high--;
                size >>= 1;
                VM_BUG_ON_PAGE(bad_range(zone, &page[size]), &page[size]);
@@ -2028,7 +2085,7 @@ static inline void expand(struct zone *zone, struct page *page,
                if (set_page_guard(zone, &page[size], high, migratetype))
                        continue;
 
-               add_to_free_area(&page[size], area, migratetype);
+               add_to_free_list(&page[size], zone, high, migratetype);
                set_page_order(&page[size], high);
        }
 }
@@ -2186,8 +2243,8 @@ struct page *__rmqueue_smallest(struct zone *zone, unsigned int order,
                page = get_page_from_free_area(area, migratetype);
                if (!page)
                        continue;
-               del_page_from_free_area(page, area);
-               expand(zone, page, order, current_order, area, migratetype);
+               del_page_from_free_list(page, zone, current_order);
+               expand(zone, page, order, current_order, migratetype);
                set_pcppage_migratetype(page, migratetype);
                return page;
        }
@@ -2261,7 +2318,7 @@ static int move_freepages(struct zone *zone,
                VM_BUG_ON_PAGE(page_zone(page) != zone, page);
 
                order = page_order(page);
-               move_to_free_area(page, &zone->free_area[order], migratetype);
+               move_to_free_list(page, zone, order, migratetype);
                page += 1 << order;
                pages_moved += 1 << order;
        }
@@ -2344,6 +2401,14 @@ static inline void boost_watermark(struct zone *zone)
 
        if (!watermark_boost_factor)
                return;
+       /*
+        * Don't bother in zones that are unlikely to produce results.
+        * On small machines, including kdump capture kernels running
+        * in a small area, boosting the watermark can cause an out of
+        * memory situation immediately.
+        */
+       if ((pageblock_nr_pages * 4) > zone_managed_pages(zone))
+               return;
 
        max_boost = mult_frac(zone->_watermark[WMARK_HIGH],
                        watermark_boost_factor, 10000);
@@ -2377,7 +2442,6 @@ static void steal_suitable_fallback(struct zone *zone, struct page *page,
                unsigned int alloc_flags, int start_type, bool whole_block)
 {
        unsigned int current_order = page_order(page);
-       struct free_area *area;
        int free_pages, movable_pages, alike_pages;
        int old_block_type;
 
@@ -2448,8 +2512,7 @@ static void steal_suitable_fallback(struct zone *zone, struct page *page,
        return;
 
 single_page:
-       area = &zone->free_area[current_order];
-       move_to_free_area(page, area, start_type);
+       move_to_free_list(page, zone, current_order, start_type);
 }
 
 /*
@@ -3120,7 +3183,6 @@ EXPORT_SYMBOL_GPL(split_page);
 
 int __isolate_free_page(struct page *page, unsigned int order)
 {
-       struct free_area *area = &page_zone(page)->free_area[order];
        unsigned long watermark;
        struct zone *zone;
        int mt;
@@ -3146,7 +3208,7 @@ int __isolate_free_page(struct page *page, unsigned int order)
 
        /* Remove page from free list */
 
-       del_page_from_free_area(page, area);
+       del_page_from_free_list(page, zone, order);
 
        /*
         * Set the pageblock if the isolated page is at least half of a
@@ -3167,6 +3229,26 @@ int __isolate_free_page(struct page *page, unsigned int order)
        return 1UL << order;
 }
 
+/**
+ * __putback_isolated_page - Return a now-isolated page back where we got it
+ * @page: Page that was isolated
+ * @order: Order of the isolated page
+ * @mt: The page's pageblock's migratetype
+ *
+ * This function is meant to return a page pulled from the free lists via
+ * __isolate_free_page back to the free lists they were pulled from.
+ */
+void __putback_isolated_page(struct page *page, unsigned int order, int mt)
+{
+       struct zone *zone = page_zone(page);
+
+       /* zone lock should be held when this function is called */
+       lockdep_assert_held(&zone->lock);
+
+       /* Return isolated page to tail of freelist. */
+       __free_one_page(page, page_to_pfn(page), zone, order, mt, false);
+}
+
 /*
  * Update NUMA hit/miss statistics
  *
@@ -8713,7 +8795,7 @@ __offline_isolated_pages(unsigned long start_pfn, unsigned long end_pfn)
                BUG_ON(!PageBuddy(page));
                order = page_order(page);
                offlined_pages += 1 << order;
-               del_page_from_free_area(page, &zone->free_area[order]);
+               del_page_from_free_list(page, zone, order);
                pfn += (1 << order);
        }
        spin_unlock_irqrestore(&zone->lock, flags);