243 lines
7.4 KiB
Diff
243 lines
7.4 KiB
Diff
From d22cba7e76710f715c9096a58b3bb0ce8b58640a Mon Sep 17 00:00:00 2001
|
|
Message-Id: <d22cba7e76710f715c9096a58b3bb0ce8b58640a.1596234183.git.zanussi@kernel.org>
|
|
In-Reply-To: <378ee68279f6a7631221f2670a9298620148690d.1596234183.git.zanussi@kernel.org>
|
|
References: <378ee68279f6a7631221f2670a9298620148690d.1596234183.git.zanussi@kernel.org>
|
|
From: Ingo Molnar <mingo@elte.hu>
|
|
Date: Fri, 3 Jul 2009 08:29:37 -0500
|
|
Subject: [PATCH 076/329] mm: page_alloc: rt-friendly per-cpu pages
|
|
Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/4.19/older/patches-4.19.135-rt60.tar.xz
|
|
|
|
rt-friendly per-cpu pages: convert the irqs-off per-cpu locking
|
|
method into a preemptible, explicit-per-cpu-locks method.
|
|
|
|
Contains fixes from:
|
|
Peter Zijlstra <a.p.zijlstra@chello.nl>
|
|
Thomas Gleixner <tglx@linutronix.de>
|
|
|
|
Signed-off-by: Ingo Molnar <mingo@elte.hu>
|
|
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
|
|
---
|
|
mm/page_alloc.c | 63 +++++++++++++++++++++++++++++++++----------------
|
|
1 file changed, 43 insertions(+), 20 deletions(-)
|
|
|
|
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
|
|
index 6c45b7713e56..63bf99bdcabc 100644
|
|
--- a/mm/page_alloc.c
|
|
+++ b/mm/page_alloc.c
|
|
@@ -60,6 +60,7 @@
|
|
#include <linux/hugetlb.h>
|
|
#include <linux/sched/rt.h>
|
|
#include <linux/sched/mm.h>
|
|
+#include <linux/locallock.h>
|
|
#include <linux/page_owner.h>
|
|
#include <linux/kthread.h>
|
|
#include <linux/memcontrol.h>
|
|
@@ -291,6 +292,18 @@ EXPORT_SYMBOL(nr_node_ids);
|
|
EXPORT_SYMBOL(nr_online_nodes);
|
|
#endif
|
|
|
|
+static DEFINE_LOCAL_IRQ_LOCK(pa_lock);
|
|
+
|
|
+#ifdef CONFIG_PREEMPT_RT_BASE
|
|
+# define cpu_lock_irqsave(cpu, flags) \
|
|
+ local_lock_irqsave_on(pa_lock, flags, cpu)
|
|
+# define cpu_unlock_irqrestore(cpu, flags) \
|
|
+ local_unlock_irqrestore_on(pa_lock, flags, cpu)
|
|
+#else
|
|
+# define cpu_lock_irqsave(cpu, flags) local_irq_save(flags)
|
|
+# define cpu_unlock_irqrestore(cpu, flags) local_irq_restore(flags)
|
|
+#endif
|
|
+
|
|
int page_group_by_mobility_disabled __read_mostly;
|
|
|
|
#ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT
|
|
@@ -1296,10 +1309,10 @@ static void __free_pages_ok(struct page *page, unsigned int order)
|
|
return;
|
|
|
|
migratetype = get_pfnblock_migratetype(page, pfn);
|
|
- local_irq_save(flags);
|
|
+ local_lock_irqsave(pa_lock, flags);
|
|
__count_vm_events(PGFREE, 1 << order);
|
|
free_one_page(page_zone(page), page, pfn, order, migratetype);
|
|
- local_irq_restore(flags);
|
|
+ local_unlock_irqrestore(pa_lock, flags);
|
|
}
|
|
|
|
static void __init __free_pages_boot_core(struct page *page, unsigned int order)
|
|
@@ -2564,13 +2577,13 @@ void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp)
|
|
int to_drain, batch;
|
|
LIST_HEAD(dst);
|
|
|
|
- local_irq_save(flags);
|
|
+ local_lock_irqsave(pa_lock, flags);
|
|
batch = READ_ONCE(pcp->batch);
|
|
to_drain = min(pcp->count, batch);
|
|
if (to_drain > 0)
|
|
isolate_pcp_pages(to_drain, pcp, &dst);
|
|
|
|
- local_irq_restore(flags);
|
|
+ local_unlock_irqrestore(pa_lock, flags);
|
|
|
|
if (to_drain > 0)
|
|
free_pcppages_bulk(zone, &dst, false);
|
|
@@ -2592,7 +2605,7 @@ static void drain_pages_zone(unsigned int cpu, struct zone *zone)
|
|
LIST_HEAD(dst);
|
|
int count;
|
|
|
|
- local_irq_save(flags);
|
|
+ cpu_lock_irqsave(cpu, flags);
|
|
pset = per_cpu_ptr(zone->pageset, cpu);
|
|
|
|
pcp = &pset->pcp;
|
|
@@ -2600,7 +2613,7 @@ static void drain_pages_zone(unsigned int cpu, struct zone *zone)
|
|
if (count)
|
|
isolate_pcp_pages(count, pcp, &dst);
|
|
|
|
- local_irq_restore(flags);
|
|
+ cpu_unlock_irqrestore(cpu, flags);
|
|
|
|
if (count)
|
|
free_pcppages_bulk(zone, &dst, false);
|
|
@@ -2638,6 +2651,7 @@ void drain_local_pages(struct zone *zone)
|
|
drain_pages(cpu);
|
|
}
|
|
|
|
+#ifndef CONFIG_PREEMPT_RT_BASE
|
|
static void drain_local_pages_wq(struct work_struct *work)
|
|
{
|
|
/*
|
|
@@ -2651,6 +2665,7 @@ static void drain_local_pages_wq(struct work_struct *work)
|
|
drain_local_pages(NULL);
|
|
preempt_enable();
|
|
}
|
|
+#endif
|
|
|
|
/*
|
|
* Spill all the per-cpu pages from all CPUs back into the buddy allocator.
|
|
@@ -2717,7 +2732,14 @@ void drain_all_pages(struct zone *zone)
|
|
else
|
|
cpumask_clear_cpu(cpu, &cpus_with_pcps);
|
|
}
|
|
-
|
|
+#ifdef CONFIG_PREEMPT_RT_BASE
|
|
+ for_each_cpu(cpu, &cpus_with_pcps) {
|
|
+ if (zone)
|
|
+ drain_pages_zone(cpu, zone);
|
|
+ else
|
|
+ drain_pages(cpu);
|
|
+ }
|
|
+#else
|
|
for_each_cpu(cpu, &cpus_with_pcps) {
|
|
struct work_struct *work = per_cpu_ptr(&pcpu_drain, cpu);
|
|
INIT_WORK(work, drain_local_pages_wq);
|
|
@@ -2725,6 +2747,7 @@ void drain_all_pages(struct zone *zone)
|
|
}
|
|
for_each_cpu(cpu, &cpus_with_pcps)
|
|
flush_work(per_cpu_ptr(&pcpu_drain, cpu));
|
|
+#endif
|
|
|
|
mutex_unlock(&pcpu_drain_mutex);
|
|
}
|
|
@@ -2844,9 +2867,9 @@ void free_unref_page(struct page *page)
|
|
if (!free_unref_page_prepare(page, pfn))
|
|
return;
|
|
|
|
- local_irq_save(flags);
|
|
+ local_lock_irqsave(pa_lock, flags);
|
|
free_unref_page_commit(page, pfn, &dst);
|
|
- local_irq_restore(flags);
|
|
+ local_unlock_irqrestore(pa_lock, flags);
|
|
if (!list_empty(&dst))
|
|
free_pcppages_bulk(zone, &dst, false);
|
|
}
|
|
@@ -2873,7 +2896,7 @@ void free_unref_page_list(struct list_head *list)
|
|
set_page_private(page, pfn);
|
|
}
|
|
|
|
- local_irq_save(flags);
|
|
+ local_lock_irqsave(pa_lock, flags);
|
|
list_for_each_entry_safe(page, next, list, lru) {
|
|
unsigned long pfn = page_private(page);
|
|
enum zone_type type;
|
|
@@ -2888,12 +2911,12 @@ void free_unref_page_list(struct list_head *list)
|
|
* a large list of pages to free.
|
|
*/
|
|
if (++batch_count == SWAP_CLUSTER_MAX) {
|
|
- local_irq_restore(flags);
|
|
+ local_unlock_irqrestore(pa_lock, flags);
|
|
batch_count = 0;
|
|
- local_irq_save(flags);
|
|
+ local_lock_irqsave(pa_lock, flags);
|
|
}
|
|
}
|
|
- local_irq_restore(flags);
|
|
+ local_unlock_irqrestore(pa_lock, flags);
|
|
|
|
for (i = 0; i < __MAX_NR_ZONES; ) {
|
|
struct page *page;
|
|
@@ -3042,7 +3065,7 @@ static struct page *rmqueue_pcplist(struct zone *preferred_zone,
|
|
struct page *page;
|
|
unsigned long flags;
|
|
|
|
- local_irq_save(flags);
|
|
+ local_lock_irqsave(pa_lock, flags);
|
|
pcp = &this_cpu_ptr(zone->pageset)->pcp;
|
|
list = &pcp->lists[migratetype];
|
|
page = __rmqueue_pcplist(zone, migratetype, pcp, list);
|
|
@@ -3050,7 +3073,7 @@ static struct page *rmqueue_pcplist(struct zone *preferred_zone,
|
|
__count_zid_vm_events(PGALLOC, page_zonenum(page), 1 << order);
|
|
zone_statistics(preferred_zone, zone);
|
|
}
|
|
- local_irq_restore(flags);
|
|
+ local_unlock_irqrestore(pa_lock, flags);
|
|
return page;
|
|
}
|
|
|
|
@@ -3077,7 +3100,7 @@ struct page *rmqueue(struct zone *preferred_zone,
|
|
* allocate greater than order-1 page units with __GFP_NOFAIL.
|
|
*/
|
|
WARN_ON_ONCE((gfp_flags & __GFP_NOFAIL) && (order > 1));
|
|
- spin_lock_irqsave(&zone->lock, flags);
|
|
+ local_spin_lock_irqsave(pa_lock, &zone->lock, flags);
|
|
|
|
do {
|
|
page = NULL;
|
|
@@ -3097,14 +3120,14 @@ struct page *rmqueue(struct zone *preferred_zone,
|
|
|
|
__count_zid_vm_events(PGALLOC, page_zonenum(page), 1 << order);
|
|
zone_statistics(preferred_zone, zone);
|
|
- local_irq_restore(flags);
|
|
+ local_unlock_irqrestore(pa_lock, flags);
|
|
|
|
out:
|
|
VM_BUG_ON_PAGE(page && bad_range(zone, page), page);
|
|
return page;
|
|
|
|
failed:
|
|
- local_irq_restore(flags);
|
|
+ local_unlock_irqrestore(pa_lock, flags);
|
|
return NULL;
|
|
}
|
|
|
|
@@ -8125,7 +8148,7 @@ void zone_pcp_reset(struct zone *zone)
|
|
struct per_cpu_pageset *pset;
|
|
|
|
/* avoid races with drain_pages() */
|
|
- local_irq_save(flags);
|
|
+ local_lock_irqsave(pa_lock, flags);
|
|
if (zone->pageset != &boot_pageset) {
|
|
for_each_online_cpu(cpu) {
|
|
pset = per_cpu_ptr(zone->pageset, cpu);
|
|
@@ -8134,7 +8157,7 @@ void zone_pcp_reset(struct zone *zone)
|
|
free_percpu(zone->pageset);
|
|
zone->pageset = &boot_pageset;
|
|
}
|
|
- local_irq_restore(flags);
|
|
+ local_unlock_irqrestore(pa_lock, flags);
|
|
}
|
|
|
|
#ifdef CONFIG_MEMORY_HOTREMOVE
|
|
--
|
|
2.17.1
|
|
|