mm: introduce page reference manipulation functions
[linux-2.6-block.git] / mm / page_alloc.c
index c46b75d14b6f8732b513065f1bd79d124d703579..30134a8f7cc89988992dcab363e00c447aec97c1 100644 (file)
@@ -249,6 +249,7 @@ compound_page_dtor * const compound_page_dtors[] = {
 
 int min_free_kbytes = 1024;
 int user_min_free_kbytes = -1;
+int watermark_scale_factor = 10;
 
 static unsigned long __meminitdata nr_kernel_pages;
 static unsigned long __meminitdata nr_all_pages;
@@ -498,6 +499,7 @@ void prep_compound_page(struct page *page, unsigned int order)
 unsigned int _debug_guardpage_minorder;
 bool _debug_pagealloc_enabled __read_mostly
                        = IS_ENABLED(CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT);
+EXPORT_SYMBOL(_debug_pagealloc_enabled);
 bool _debug_guardpage_enabled __read_mostly;
 
 static int __init early_debug_pagealloc(char *buf)
@@ -764,7 +766,7 @@ static inline int free_pages_check(struct page *page)
                bad_reason = "nonzero mapcount";
        if (unlikely(page->mapping != NULL))
                bad_reason = "non-NULL mapping";
-       if (unlikely(atomic_read(&page->_count) != 0))
+       if (unlikely(page_ref_count(page) != 0))
                bad_reason = "nonzero _count";
        if (unlikely(page->flags & PAGE_FLAGS_CHECK_AT_FREE)) {
                bad_reason = "PAGE_FLAGS_CHECK_AT_FREE flag(s) set";
@@ -1460,7 +1462,7 @@ static inline int check_new_page(struct page *page)
                bad_reason = "nonzero mapcount";
        if (unlikely(page->mapping != NULL))
                bad_reason = "non-NULL mapping";
-       if (unlikely(atomic_read(&page->_count) != 0))
+       if (unlikely(page_ref_count(page) != 0))
                bad_reason = "nonzero _count";
        if (unlikely(page->flags & __PG_HWPOISON)) {
                bad_reason = "HWPoisoned (hardware-corrupted)";
@@ -3117,14 +3119,6 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
                                (__GFP_ATOMIC|__GFP_DIRECT_RECLAIM)))
                gfp_mask &= ~__GFP_ATOMIC;
 
-       /*
-        * If this allocation cannot block and it is for a specific node, then
-        * fail early.  There's no need to wakeup kswapd or retry for a
-        * speculative node-specific allocation.
-        */
-       if (IS_ENABLED(CONFIG_NUMA) && (gfp_mask & __GFP_THISNODE) && !can_direct_reclaim)
-               goto nopage;
-
 retry:
        if (gfp_mask & __GFP_KSWAPD_RECLAIM)
                wake_all_kswapds(order, ac);
@@ -3481,7 +3475,7 @@ refill:
                /* Even if we own the page, we do not use atomic_set().
                 * This would break get_page_unless_zero() users.
                 */
-               atomic_add(size - 1, &page->_count);
+               page_ref_add(page, size - 1);
 
                /* reset page count bias and offset to start of new frag */
                nc->pfmemalloc = page_is_pfmemalloc(page);
@@ -3493,7 +3487,7 @@ refill:
        if (unlikely(offset < 0)) {
                page = virt_to_page(nc->va);
 
-               if (!atomic_sub_and_test(nc->pagecnt_bias, &page->_count))
+               if (!page_ref_sub_and_test(page, nc->pagecnt_bias))
                        goto refill;
 
 #if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE)
@@ -3501,7 +3495,7 @@ refill:
                size = nc->size;
 #endif
                /* OK, page count is 0, we can safely set it */
-               atomic_set(&page->_count, size);
+               set_page_count(page, size);
 
                /* reset page count bias and offset to start of new frag */
                nc->pagecnt_bias = size;
@@ -3712,6 +3706,49 @@ static inline void show_node(struct zone *zone)
                printk("Node %d ", zone_to_nid(zone));
 }
 
+long si_mem_available(void)
+{
+       long available;
+       unsigned long pagecache;
+       unsigned long wmark_low = 0;
+       unsigned long pages[NR_LRU_LISTS];
+       struct zone *zone;
+       int lru;
+
+       for (lru = LRU_BASE; lru < NR_LRU_LISTS; lru++)
+               pages[lru] = global_page_state(NR_LRU_BASE + lru);
+
+       for_each_zone(zone)
+               wmark_low += zone->watermark[WMARK_LOW];
+
+       /*
+        * Estimate the amount of memory available for userspace allocations,
+        * without causing swapping.
+        */
+       available = global_page_state(NR_FREE_PAGES) - totalreserve_pages;
+
+       /*
+        * Not all the page cache can be freed, otherwise the system will
+        * start swapping. Assume at least half of the page cache, or the
+        * low watermark worth of cache, needs to stay.
+        */
+       pagecache = pages[LRU_ACTIVE_FILE] + pages[LRU_INACTIVE_FILE];
+       pagecache -= min(pagecache / 2, wmark_low);
+       available += pagecache;
+
+       /*
+        * Part of the reclaimable slab consists of items that are in use,
+        * and cannot be freed. Cap this estimate at the low watermark.
+        */
+       available += global_page_state(NR_SLAB_RECLAIMABLE) -
+                    min(global_page_state(NR_SLAB_RECLAIMABLE) / 2, wmark_low);
+
+       if (available < 0)
+               available = 0;
+       return available;
+}
+EXPORT_SYMBOL_GPL(si_mem_available);
+
 void si_meminfo(struct sysinfo *val)
 {
        val->totalram = totalram_pages;
@@ -5404,6 +5441,9 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat)
 #endif
        init_waitqueue_head(&pgdat->kswapd_wait);
        init_waitqueue_head(&pgdat->pfmemalloc_wait);
+#ifdef CONFIG_COMPACTION
+       init_waitqueue_head(&pgdat->kcompactd_wait);
+#endif
        pgdat_page_ext_init(pgdat);
 
        for (j = 0; j < MAX_NR_ZONES; j++) {
@@ -6300,8 +6340,17 @@ static void __setup_per_zone_wmarks(void)
                        zone->watermark[WMARK_MIN] = tmp;
                }
 
-               zone->watermark[WMARK_LOW]  = min_wmark_pages(zone) + (tmp >> 2);
-               zone->watermark[WMARK_HIGH] = min_wmark_pages(zone) + (tmp >> 1);
+               /*
+                * Set the kswapd watermarks distance according to the
+                * scale factor in proportion to available memory, but
+                * ensure a minimum size on small systems.
+                */
+               tmp = max_t(u64, tmp >> 2,
+                           mult_frac(zone->managed_pages,
+                                     watermark_scale_factor, 10000));
+
+               zone->watermark[WMARK_LOW]  = min_wmark_pages(zone) + tmp;
+               zone->watermark[WMARK_HIGH] = min_wmark_pages(zone) + tmp * 2;
 
                __mod_zone_page_state(zone, NR_ALLOC_BATCH,
                        high_wmark_pages(zone) - low_wmark_pages(zone) -
@@ -6442,6 +6491,21 @@ int min_free_kbytes_sysctl_handler(struct ctl_table *table, int write,
        return 0;
 }
 
+int watermark_scale_factor_sysctl_handler(struct ctl_table *table, int write,
+       void __user *buffer, size_t *length, loff_t *ppos)
+{
+       int rc;
+
+       rc = proc_dointvec_minmax(table, write, buffer, length, ppos);
+       if (rc)
+               return rc;
+
+       if (write)
+               setup_per_zone_wmarks();
+
+       return 0;
+}
+
 #ifdef CONFIG_NUMA
 int sysctl_min_unmapped_ratio_sysctl_handler(struct ctl_table *table, int write,
        void __user *buffer, size_t *length, loff_t *ppos)
@@ -6788,7 +6852,7 @@ bool has_unmovable_pages(struct zone *zone, struct page *page, int count,
                 * This check already skips compound tails of THP
                 * because their page->_count is zero at all time.
                 */
-               if (!atomic_read(&page->_count)) {
+               if (!page_ref_count(page)) {
                        if (PageBuddy(page))
                                iter += (1 << page_order(page)) - 1;
                        continue;
@@ -7152,7 +7216,6 @@ __offline_isolated_pages(unsigned long start_pfn, unsigned long end_pfn)
 }
 #endif
 
-#ifdef CONFIG_MEMORY_FAILURE
 bool is_free_buddy_page(struct page *page)
 {
        struct zone *zone = page_zone(page);
@@ -7171,4 +7234,3 @@ bool is_free_buddy_page(struct page *page)
 
        return order < MAX_ORDER;
 }
-#endif