212 lines
6.1 KiB
Diff
212 lines
6.1 KiB
Diff
|
From f74dad392178d2551b58d75461a74d2215525c28 Mon Sep 17 00:00:00 2001
|
||
|
From: Ingo Molnar <mingo@elte.hu>
|
||
|
Date: Fri, 3 Jul 2009 08:29:37 -0500
|
||
|
Subject: [PATCH 099/365] mm: page_alloc: rt-friendly per-cpu pages
|
||
|
|
||
|
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>
|
||
|
|
||
|
Change-Id: I773300f1a0c019b1224a8961f562e75ac731d6c4
|
||
|
Signed-off-by: Ingo Molnar <mingo@elte.hu>
|
||
|
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
|
||
|
---
|
||
|
mm/page_alloc.c | 60 +++++++++++++++++++++++++++++++++++--------------
|
||
|
1 file changed, 43 insertions(+), 17 deletions(-)
|
||
|
|
||
|
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
|
||
|
index 35353d75b884..4e00da51629b 100644
|
||
|
--- a/mm/page_alloc.c
|
||
|
+++ b/mm/page_alloc.c
|
||
|
@@ -61,6 +61,7 @@
|
||
|
#include <linux/page_ext.h>
|
||
|
#include <linux/hugetlb.h>
|
||
|
#include <linux/sched/rt.h>
|
||
|
+#include <linux/locallock.h>
|
||
|
#include <linux/page_owner.h>
|
||
|
#include <linux/kthread.h>
|
||
|
#include <linux/memcontrol.h>
|
||
|
@@ -294,6 +295,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) \
|
||
|
+ spin_lock_irqsave(&per_cpu(pa_lock, cpu).lock, flags)
|
||
|
+# define cpu_unlock_irqrestore(cpu, flags) \
|
||
|
+ spin_unlock_irqrestore(&per_cpu(pa_lock, cpu).lock, flags)
|
||
|
+#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
|
||
|
@@ -1282,10 +1295,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)
|
||
|
@@ -2303,14 +2316,14 @@ void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp)
|
||
|
unsigned long flags;
|
||
|
int to_drain, batch;
|
||
|
|
||
|
- 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) {
|
||
|
free_pcppages_bulk(zone, to_drain, pcp);
|
||
|
pcp->count -= to_drain;
|
||
|
}
|
||
|
- local_irq_restore(flags);
|
||
|
+ local_unlock_irqrestore(pa_lock, flags);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
@@ -2327,7 +2340,7 @@ static void drain_pages_zone(unsigned int cpu, struct zone *zone)
|
||
|
struct per_cpu_pageset *pset;
|
||
|
struct per_cpu_pages *pcp;
|
||
|
|
||
|
- local_irq_save(flags);
|
||
|
+ cpu_lock_irqsave(cpu, flags);
|
||
|
pset = per_cpu_ptr(zone->pageset, cpu);
|
||
|
|
||
|
pcp = &pset->pcp;
|
||
|
@@ -2335,7 +2348,7 @@ static void drain_pages_zone(unsigned int cpu, struct zone *zone)
|
||
|
free_pcppages_bulk(zone, pcp->count, pcp);
|
||
|
pcp->count = 0;
|
||
|
}
|
||
|
- local_irq_restore(flags);
|
||
|
+ cpu_unlock_irqrestore(cpu, flags);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
@@ -2422,7 +2435,17 @@ void drain_all_pages(struct zone *zone)
|
||
|
else
|
||
|
cpumask_clear_cpu(cpu, &cpus_with_pcps);
|
||
|
}
|
||
|
- on_each_cpu_mask(&cpus_with_pcps, drain_local_pages, zone, 1);
|
||
|
+#ifndef CONFIG_PREEMPT_RT_BASE
|
||
|
+ on_each_cpu_mask(&cpus_with_pcps, (smp_call_func_t) drain_local_pages,
|
||
|
+ zone, 1);
|
||
|
+#else
|
||
|
+ for_each_cpu(cpu, &cpus_with_pcps) {
|
||
|
+ if (zone)
|
||
|
+ drain_pages_zone(cpu, zone);
|
||
|
+ else
|
||
|
+ drain_pages(cpu);
|
||
|
+ }
|
||
|
+#endif
|
||
|
}
|
||
|
|
||
|
#ifdef CONFIG_HIBERNATION
|
||
|
@@ -2482,7 +2505,7 @@ void free_hot_cold_page(struct page *page, bool cold)
|
||
|
|
||
|
migratetype = get_pfnblock_migratetype(page, pfn);
|
||
|
set_pcppage_migratetype(page, migratetype);
|
||
|
- local_irq_save(flags);
|
||
|
+ local_lock_irqsave(pa_lock, flags);
|
||
|
__count_vm_event(PGFREE);
|
||
|
|
||
|
/*
|
||
|
@@ -2513,7 +2536,7 @@ void free_hot_cold_page(struct page *page, bool cold)
|
||
|
}
|
||
|
|
||
|
out:
|
||
|
- local_irq_restore(flags);
|
||
|
+ local_unlock_irqrestore(pa_lock, flags);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
@@ -2648,7 +2671,7 @@ struct page *buffered_rmqueue(struct zone *preferred_zone,
|
||
|
struct per_cpu_pages *pcp;
|
||
|
struct list_head *list;
|
||
|
|
||
|
- local_irq_save(flags);
|
||
|
+ local_lock_irqsave(pa_lock, flags);
|
||
|
do {
|
||
|
pcp = &this_cpu_ptr(zone->pageset)->pcp;
|
||
|
list = &pcp->lists[migratetype];
|
||
|
@@ -2675,7 +2698,7 @@ struct page *buffered_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;
|
||
|
@@ -2687,22 +2710,24 @@ struct page *buffered_rmqueue(struct zone *preferred_zone,
|
||
|
if (!page)
|
||
|
page = __rmqueue(zone, order, migratetype);
|
||
|
} while (page && check_new_pages(page, order));
|
||
|
- spin_unlock(&zone->lock);
|
||
|
- if (!page)
|
||
|
+ if (!page) {
|
||
|
+ spin_unlock(&zone->lock);
|
||
|
goto failed;
|
||
|
+ }
|
||
|
__mod_zone_freepage_state(zone, -(1 << order),
|
||
|
get_pcppage_migratetype(page));
|
||
|
+ spin_unlock(&zone->lock);
|
||
|
}
|
||
|
|
||
|
__count_zid_vm_events(PGALLOC, page_zonenum(page), 1 << order);
|
||
|
zone_statistics(preferred_zone, zone, gfp_flags);
|
||
|
- local_irq_restore(flags);
|
||
|
+ local_unlock_irqrestore(pa_lock, flags);
|
||
|
|
||
|
VM_BUG_ON_PAGE(bad_range(zone, page), page);
|
||
|
return page;
|
||
|
|
||
|
failed:
|
||
|
- local_irq_restore(flags);
|
||
|
+ local_unlock_irqrestore(pa_lock, flags);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
@@ -6602,6 +6627,7 @@ static int page_alloc_cpu_notify(struct notifier_block *self,
|
||
|
void __init page_alloc_init(void)
|
||
|
{
|
||
|
hotcpu_notifier(page_alloc_cpu_notify, 0);
|
||
|
+ local_irq_lock_init(pa_lock);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
@@ -7445,7 +7471,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);
|
||
|
@@ -7454,7 +7480,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.28.0
|
||
|
|