From: Tejun Heo <tj@kernel.org>
To: JBeulich@novell.com, andi@firstfloor.org, mingo@elte.hu,
linux-kernel-owner@vger.kernel.org, hpa@zytor.com,
tglx@linutronix.de, linux-kernel@vger.kernel.org
Subject: Re: [PATCH UPDATED 3/4] x86: fix pageattr handling for remap percpu allocator
Date: Fri, 15 May 2009 01:21:22 +0900 [thread overview]
Message-ID: <4A0C4502.2060408@kernel.org> (raw)
In-Reply-To: <1242305390-21958-4-git-send-email-tj@kernel.org>
Remap allocator aliases a PMD page for each cpu and returns whatever
is unused to the page allocator. When the pageattr of the recycled
pages are changed, this makes the two aliases point to the overlapping
regions with different attributes which isn't allowed and known to
cause subtle data corruption in certain cases.
This can be handled in simliar manner to the x86_64 highmap alias.
pageattr code should detect if the target pages have PMD alias and
split the PMD alias and synchronize the attributes.
pcpur allocator is updated to keep the allocated PMD pages map sorted
in ascending address order and provide pcpu_pmd_remapped() function
which binary searches the array to determine whether the given address
is aliased and if so to which address. pageattr is updated to use
pcpu_pmd_remapped() to detect the PMD alias and split it up as
necessary from cpa_process_alias().
This problem has been spotted by Jan Beulich.
[ Impact: fix subtle pageattr bug ]
Signed-off-by: Tejun Heo <tj@kernel.org>
Reported-by: Jan Beulich <JBeulich@novell.com>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: Ingo Molnar <mingo@elte.hu>
---
arch/x86/include/asm/percpu.h | 9 +++++
arch/x86/kernel/setup_percpu.c | 68 ++++++++++++++++++++++++++++++++++++---
arch/x86/mm/pageattr.c | 23 +++++++++++++
3 files changed, 94 insertions(+), 6 deletions(-)
diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h
index aee103b..cad3531 100644
--- a/arch/x86/include/asm/percpu.h
+++ b/arch/x86/include/asm/percpu.h
@@ -155,6 +155,15 @@ do { \
/* We can use this directly for local CPU (faster). */
DECLARE_PER_CPU(unsigned long, this_cpu_off);
+#ifdef CONFIG_NEED_MULTIPLE_NODES
+void *pcpu_pmd_remapped(void *kaddr);
+#else
+static inline void *pcpu_pmd_remapped(void *kaddr)
+{
+ return NULL;
+}
+#endif
+
#endif /* !__ASSEMBLY__ */
#ifdef CONFIG_SMP
diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c
index c17059c..dd567a7 100644
--- a/arch/x86/kernel/setup_percpu.c
+++ b/arch/x86/kernel/setup_percpu.c
@@ -142,8 +142,8 @@ struct pcpur_ent {
void *ptr;
};
-static size_t pcpur_size __initdata;
-static struct pcpur_ent *pcpur_map __initdata;
+static size_t pcpur_size;
+static struct pcpur_ent *pcpur_map;
static struct vm_struct pcpur_vm;
static struct page * __init pcpur_get_page(unsigned int cpu, int pageno)
@@ -160,6 +160,7 @@ static ssize_t __init setup_pcpu_remap(size_t static_size)
{
size_t map_size, dyn_size;
unsigned int cpu;
+ int i, j;
ssize_t ret;
/*
@@ -229,16 +230,71 @@ static ssize_t __init setup_pcpu_remap(size_t static_size)
ret = pcpu_setup_first_chunk(pcpur_get_page, static_size,
PERCPU_FIRST_CHUNK_RESERVE, dyn_size,
PMD_SIZE, pcpur_vm.addr, NULL);
- goto out_free_map;
+
+ /* sort pcpur_map array for pcpu_pmd_remapped() */
+ for (i = 0; i < num_possible_cpus() - 1; i++)
+ for (j = i + 1; j < num_possible_cpus(); j++)
+ if (pcpur_map[i].ptr > pcpur_map[j].ptr) {
+ struct pcpur_ent tmp = pcpur_map[i];
+ pcpur_map[i] = pcpur_map[j];
+ pcpur_map[j] = tmp;
+ }
+
+ return ret;
enomem:
for_each_possible_cpu(cpu)
if (pcpur_map[cpu].ptr)
free_bootmem(__pa(pcpur_map[cpu].ptr), PMD_SIZE);
- ret = -ENOMEM;
-out_free_map:
free_bootmem(__pa(pcpur_map), map_size);
- return ret;
+ return -ENOMEM;
+}
+
+/**
+ * pcpu_pmd_remapped - determine whether a kaddr is in pcpur recycled area
+ * @kaddr: the kernel address in question
+ *
+ * Determine whether @kaddr falls in the pcpur recycled area. This is
+ * used by pageattr to detect VM aliases and break up the pcpu PMD
+ * mapping such that the same physical page is not mapped under
+ * different attributes.
+ *
+ * The recycled area is always at the tail of a partially used PMD
+ * page.
+ *
+ * RETURNS:
+ * Address of corresponding remapped pcpu address if match is found;
+ * otherwise, NULL.
+ */
+void *pcpu_pmd_remapped(void *kaddr)
+{
+ void *pmd_addr = (void *)((unsigned long)kaddr & PMD_MASK);
+ unsigned long offset = (unsigned long)kaddr & ~PMD_MASK;
+ int left = 0, right = num_possible_cpus() - 1;
+ int pos;
+
+ /* pcpur in use at all? */
+ if (!pcpur_map)
+ return NULL;
+
+ /* okay, perform binary search */
+ while (left <= right) {
+ pos = (left + right) / 2;
+
+ if (pcpur_map[pos].ptr < pmd_addr)
+ left = pos + 1;
+ else if (pcpur_map[pos].ptr > pmd_addr)
+ right = pos - 1;
+ else {
+ /* it shouldn't be in the area for the first chunk */
+ WARN_ON(offset < pcpur_size);
+
+ return pcpur_vm.addr +
+ pcpur_map[pos].cpu * PMD_SIZE + offset;
+ }
+ }
+
+ return NULL;
}
#else
static ssize_t __init setup_pcpu_remap(size_t static_size)
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index 8bc64b0..a1bcead 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -11,6 +11,7 @@
#include <linux/interrupt.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
+#include <linux/pfn.h>
#include <asm/e820.h>
#include <asm/processor.h>
@@ -687,6 +688,7 @@ static int cpa_process_alias(struct cpa_data *cpa)
{
struct cpa_data alias_cpa;
unsigned long temp_cpa_vaddr, vaddr;
+ void *remapped;
int ret;
if (cpa->pfn >= max_pfn_mapped)
@@ -742,6 +744,27 @@ static int cpa_process_alias(struct cpa_data *cpa)
}
#endif
+ /*
+ * If the PMD page was partially used for per-cpu remapping,
+ * the remapped area needs to be split and modified. Note
+ * that the partial recycling only happens at the tail of a
+ * partially used PMD page, so touching single PMD page is
+ * always enough.
+ */
+ remapped = pcpu_pmd_remapped((void *)vaddr);
+ if (remapped) {
+ int max_pages = PFN_DOWN(PMD_SIZE - (vaddr & ~PMD_MASK));
+
+ alias_cpa = *cpa;
+ temp_cpa_vaddr = (unsigned long)remapped;
+ alias_cpa.vaddr = &temp_cpa_vaddr;
+ alias_cpa.numpages = min(alias_cpa.numpages, max_pages);
+ alias_cpa.flags &= ~(CPA_PAGES_ARRAY | CPA_ARRAY);
+ ret = __change_page_attr_set_clr(&alias_cpa, 0);
+ if (ret)
+ return ret;
+ }
+
return 0;
}
--
1.6.0.2
next prev parent reply other threads:[~2009-05-14 16:21 UTC|newest]
Thread overview: 38+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-05-14 12:49 [GIT PATCH] x86,percpu: fix pageattr handling with remap allocator Tejun Heo
2009-05-14 12:49 ` [PATCH 1/4] x86: prepare setup_pcpu_remap() for pageattr fix Tejun Heo
2009-05-14 12:49 ` [PATCH 2/4] x86: simplify cpa_process_alias() Tejun Heo
2009-05-14 14:16 ` Jan Beulich
2009-05-14 15:37 ` Tejun Heo
2009-05-14 16:20 ` [PATCH UPDATED 2/4] x86: reorganize cpa_process_alias() Tejun Heo
2009-05-14 12:49 ` [PATCH 3/4] x86: fix pageattr handling for remap percpu allocator Tejun Heo
2009-05-14 16:21 ` Tejun Heo [this message]
2009-05-14 12:49 ` [PATCH 4/4] x86: implement percpu_alloc kernel parameter Tejun Heo
2009-05-14 14:28 ` [GIT PATCH] x86,percpu: fix pageattr handling with remap allocator Jan Beulich
2009-05-14 15:55 ` Tejun Heo
2009-05-15 7:47 ` Jan Beulich
2009-05-15 8:11 ` Tejun Heo
2009-05-15 8:22 ` Jan Beulich
2009-05-15 8:27 ` Tejun Heo
2009-05-14 16:22 ` Tejun Heo
2009-05-15 4:00 ` Tejun Heo
2009-05-15 4:36 ` David Miller
2009-05-15 4:48 ` Tejun Heo
2009-05-16 1:17 ` Suresh Siddha
2009-05-16 15:16 ` Tejun Heo
2009-05-16 19:09 ` Suresh Siddha
2009-05-17 1:23 ` Tejun Heo
2009-05-18 19:20 ` Suresh Siddha
2009-05-18 19:41 ` H. Peter Anvin
2009-05-18 21:07 ` Suresh Siddha
2009-05-19 1:28 ` Tejun Heo
2009-05-20 23:01 ` Suresh Siddha
2009-05-21 0:08 ` Tejun Heo
2009-05-21 0:36 ` Suresh Siddha
2009-05-21 1:46 ` Tejun Heo
2009-05-21 1:48 ` Tejun Heo
2009-05-21 19:10 ` Suresh Siddha
2009-05-21 23:18 ` Tejun Heo
2009-05-22 0:55 ` Suresh Siddha
2009-05-19 9:44 ` Tejun Heo
2009-05-20 7:54 ` Ingo Molnar
2009-05-20 7:57 ` Tejun Heo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4A0C4502.2060408@kernel.org \
--to=tj@kernel.org \
--cc=JBeulich@novell.com \
--cc=andi@firstfloor.org \
--cc=hpa@zytor.com \
--cc=linux-kernel-owner@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@elte.hu \
--cc=tglx@linutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox