io_uring: make cached_cq_overflow non atomic_t
[linux-2.6-microblaze.git] / mm / swap.c
index d16d65d..47a4768 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -348,7 +348,7 @@ static bool need_activate_page_drain(int cpu)
        return pagevec_count(&per_cpu(lru_pvecs.activate_page, cpu)) != 0;
 }
 
-void activate_page(struct page *page)
+static void activate_page(struct page *page)
 {
        page = compound_head(page);
        if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) {
@@ -368,7 +368,7 @@ static inline void activate_page_drain(int cpu)
 {
 }
 
-void activate_page(struct page *page)
+static void activate_page(struct page *page)
 {
        pg_data_t *pgdat = page_pgdat(page);
 
@@ -481,9 +481,7 @@ EXPORT_SYMBOL(lru_cache_add);
  * @vma:   vma in which page is mapped for determining reclaimability
  *
  * Place @page on the inactive or unevictable LRU list, depending on its
- * evictability.  Note that if the page is not evictable, it goes
- * directly back onto it's zone's unevictable list, it does NOT use a
- * per cpu pagevec.
+ * evictability.
  */
 void lru_cache_add_inactive_or_unevictable(struct page *page,
                                         struct vm_area_struct *vma)
@@ -494,14 +492,14 @@ void lru_cache_add_inactive_or_unevictable(struct page *page,
 
        unevictable = (vma->vm_flags & (VM_LOCKED | VM_SPECIAL)) == VM_LOCKED;
        if (unlikely(unevictable) && !TestSetPageMlocked(page)) {
+               int nr_pages = thp_nr_pages(page);
                /*
                 * We use the irq-unsafe __mod_zone_page_stat because this
                 * counter is not modified from interrupt context, and the pte
                 * lock is held(spinlock), which implies preemption disabled.
                 */
-               __mod_zone_page_state(page_zone(page), NR_MLOCK,
-                                   thp_nr_pages(page));
-               count_vm_event(UNEVICTABLE_PGMLOCKED);
+               __mod_zone_page_state(page_zone(page), NR_MLOCK, nr_pages);
+               count_vm_events(UNEVICTABLE_PGMLOCKED, nr_pages);
        }
        lru_cache_add(page);
 }
@@ -763,10 +761,20 @@ static void lru_add_drain_per_cpu(struct work_struct *dummy)
  */
 void lru_add_drain_all(void)
 {
-       static seqcount_t seqcount = SEQCNT_ZERO(seqcount);
-       static DEFINE_MUTEX(lock);
+       /*
+        * lru_drain_gen - Global pages generation number
+        *
+        * (A) Definition: global lru_drain_gen = x implies that all generations
+        *     0 < n <= x are already *scheduled* for draining.
+        *
+        * This is an optimization for the highly-contended use case where a
+        * user space workload keeps constantly generating a flow of pages for
+        * each CPU.
+        */
+       static unsigned int lru_drain_gen;
        static struct cpumask has_work;
-       int cpu, seq;
+       static DEFINE_MUTEX(lock);
+       unsigned cpu, this_gen;
 
        /*
         * Make sure nobody triggers this path before mm_percpu_wq is fully
@@ -775,21 +783,54 @@ void lru_add_drain_all(void)
        if (WARN_ON(!mm_percpu_wq))
                return;
 
-       seq = raw_read_seqcount_latch(&seqcount);
+       /*
+        * Guarantee pagevec counter stores visible by this CPU are visible to
+        * other CPUs before loading the current drain generation.
+        */
+       smp_mb();
+
+       /*
+        * (B) Locally cache global LRU draining generation number
+        *
+        * The read barrier ensures that the counter is loaded before the mutex
+        * is taken. It pairs with smp_mb() inside the mutex critical section
+        * at (D).
+        */
+       this_gen = smp_load_acquire(&lru_drain_gen);
 
        mutex_lock(&lock);
 
        /*
-        * Piggyback on drain started and finished while we waited for lock:
-        * all pages pended at the time of our enter were drained from vectors.
+        * (C) Exit the draining operation if a newer generation, from another
+        * lru_add_drain_all(), was already scheduled for draining. Check (A).
         */
-       if (__read_seqcount_retry(&seqcount, seq))
+       if (unlikely(this_gen != lru_drain_gen))
                goto done;
 
-       raw_write_seqcount_latch(&seqcount);
+       /*
+        * (D) Increment global generation number
+        *
+        * Pairs with smp_load_acquire() at (B), outside of the critical
+        * section. Use a full memory barrier to guarantee that the new global
+        * drain generation number is stored before loading pagevec counters.
+        *
+        * This pairing must be done here, before the for_each_online_cpu loop
+        * below which drains the page vectors.
+        *
+        * Let x, y, and z represent some system CPU numbers, where x < y < z.
+        * Assume CPU #z is is in the middle of the for_each_online_cpu loop
+        * below and has already reached CPU #y's per-cpu data. CPU #x comes
+        * along, adds some pages to its per-cpu vectors, then calls
+        * lru_add_drain_all().
+        *
+        * If the paired barrier is done at any later step, e.g. after the
+        * loop, CPU #x will just exit at (C) and miss flushing out all of its
+        * added pages.
+        */
+       WRITE_ONCE(lru_drain_gen, lru_drain_gen + 1);
+       smp_mb();
 
        cpumask_clear(&has_work);
-
        for_each_online_cpu(cpu) {
                struct work_struct *work = &per_cpu(lru_add_drain_work, cpu);
 
@@ -801,7 +842,7 @@ void lru_add_drain_all(void)
                    need_activate_page_drain(cpu)) {
                        INIT_WORK(work, lru_add_drain_per_cpu);
                        queue_work_on(cpu, mm_percpu_wq, work);
-                       cpumask_set_cpu(cpu, &has_work);
+                       __cpumask_set_cpu(cpu, &has_work);
                }
        }
 
@@ -816,7 +857,7 @@ void lru_add_drain_all(void)
 {
        lru_add_drain();
 }
-#endif
+#endif /* CONFIG_SMP */
 
 /**
  * release_pages - batched put_page()
@@ -848,6 +889,7 @@ void release_pages(struct page **pages, int nr)
                        locked_pgdat = NULL;
                }
 
+               page = compound_head(page);
                if (is_huge_zero_page(page))
                        continue;
 
@@ -859,7 +901,7 @@ void release_pages(struct page **pages, int nr)
                        }
                        /*
                         * ZONE_DEVICE pages that return 'false' from
-                        * put_devmap_managed_page() do not require special
+                        * page_is_devmap_managed() do not require special
                         * processing, and instead, expect a call to
                         * put_page_testzero().
                         */
@@ -869,7 +911,6 @@ void release_pages(struct page **pages, int nr)
                        }
                }
 
-               page = compound_head(page);
                if (!put_page_testzero(page))
                        continue;
 
@@ -900,8 +941,6 @@ void release_pages(struct page **pages, int nr)
                        del_page_from_lru_list(page, lruvec, page_off_lru(page));
                }
 
-               /* Clear Active bit in case of parallel mark_page_accessed */
-               __ClearPageActive(page);
                __ClearPageWaiters(page);
 
                list_add(&page->lru, &pages_to_free);