Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1668042 > unrolled thread

[PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages

Started by"Luck, Tony" <tony.luck@intel.com>
First post2017-06-16 22:20 +0200
Last post2017-06-23 23:00 +0200
Articles 17 — 5 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages "Luck, Tony" <tony.luck@intel.com> - 2017-06-16 22:20 +0200
    Re: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings  of poison pages Borislav Petkov <bp@suse.de> - 2017-06-19 20:10 +0200
      Re: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings  of poison pages "Luck, Tony" <tony.luck@intel.com> - 2017-06-21 19:50 +0200
        RE: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of  poison pages "Elliott, Robert (Persistent Memory)" <elliott@hpe.com> - 2017-06-21 22:00 +0200
          RE: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings  of poison pages "Luck, Tony" <tony.luck@intel.com> - 2017-06-21 22:20 +0200
        Re: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings  of poison pages Borislav Petkov <bp@suse.de> - 2017-06-22 11:40 +0200
          git send-email (w/o Cc: stable) "Luck, Tony" <tony.luck@intel.com> - 2017-06-30 00:20 +0200
            Re: git send-email (w/o Cc: stable) Borislav Petkov <bp@suse.de> - 2017-06-30 09:10 +0200
        RE: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of  poison pages "Elliott, Robert (Persistent Memory)" <elliott@hpe.com> - 2017-06-24 00:30 +0200
          Re: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of  poison pages Dan Williams <dan.j.williams@intel.com> - 2017-06-28 00:10 +0200
          RE: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings  of poison pages "Luck, Tony" <tony.luck@intel.com> - 2017-06-28 00:10 +0200
    Re: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings  of poison pages Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> - 2017-06-21 04:20 +0200
      Re: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings  of poison pages "Luck, Tony" <tony.luck@intel.com> - 2017-06-21 20:00 +0200
        RE: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of  poison pages "Elliott, Robert (Persistent Memory)" <elliott@hpe.com> - 2017-06-21 21:50 +0200
          RE: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings  of poison pages "Luck, Tony" <tony.luck@intel.com> - 2017-06-21 22:40 +0200
            Re: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of  poison pages Dan Williams <dan.j.williams@intel.com> - 2017-06-23 07:10 +0200
              Re: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings  of poison pages "Luck, Tony" <tony.luck@intel.com> - 2017-06-23 23:00 +0200

#1668042 — [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages

From"Luck, Tony" <tony.luck@intel.com>
Date2017-06-16 22:20 +0200
Subject[PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages
Message-ID<tT5SN-50W-5@gated-at.bofh.it>
From: Tony Luck <tony.luck@intel.com>

Speculative processor accesses may reference any memory that has a
valid page table entry.  While a speculative access won't generate
a machine check, it will log the error in a machine check bank. That
could cause escalation of a subsequent error since the overflow bit
will be then set in the machine check bank status register.

Code has to be double-plus-tricky to avoid mentioning the 1:1 virtual
address of the page we want to map out otherwise we may trigger the
very problem we are trying to avoid.  We use a non-canonical address
that passes through the usual Linux table walking code to get to the
same "pte".

Cc: Dave Hansen <dave.hansen@intel.com>
Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Cc: x86@kernel.org
Cc: linux-mm@kvack.org
Cc: linux-kernel@vger.kernel.org
Cc: stable@vger.kernel.org
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
Thanks to Dave Hansen for reviewing several iterations of this.

 arch/x86/include/asm/page_64.h   |  4 ++++
 arch/x86/kernel/cpu/mcheck/mce.c | 35 +++++++++++++++++++++++++++++++++++
 include/linux/mm_inline.h        |  6 ++++++
 mm/memory-failure.c              |  2 ++
 4 files changed, 47 insertions(+)

diff --git a/arch/x86/include/asm/page_64.h b/arch/x86/include/asm/page_64.h
index b4a0d43248cf..b50df06ad251 100644
--- a/arch/x86/include/asm/page_64.h
+++ b/arch/x86/include/asm/page_64.h
@@ -51,6 +51,10 @@ static inline void clear_page(void *page)
 
 void copy_page(void *to, void *from);
 
+#ifdef CONFIG_X86_MCE
+#define arch_unmap_kpfn arch_unmap_kpfn
+#endif
+
 #endif	/* !__ASSEMBLY__ */
 
 #ifdef CONFIG_X86_VSYSCALL_EMULATION
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index 5cfbaeb6529a..56563db0b2be 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -51,6 +51,7 @@
 #include <asm/mce.h>
 #include <asm/msr.h>
 #include <asm/reboot.h>
+#include <asm/set_memory.h>
 
 #include "mce-internal.h"
 
@@ -1056,6 +1057,40 @@ static int do_memory_failure(struct mce *m)
 	return ret;
 }
 
+#ifdef CONFIG_X86_64
+
+void arch_unmap_kpfn(unsigned long pfn)
+{
+	unsigned long decoy_addr;
+
+	/*
+	 * Unmap this page from the kernel 1:1 mappings to make sure
+	 * we don't log more errors because of speculative access to
+	 * the page.
+	 * We would like to just call:
+	 *	set_memory_np((unsigned long)pfn_to_kaddr(pfn), 1);
+	 * but doing that would radically increase the odds of a
+	 * speculative access to the posion page because we'd have
+	 * the virtual address of the kernel 1:1 mapping sitting
+	 * around in registers.
+	 * Instead we get tricky.  We create a non-canonical address
+	 * that looks just like the one we want, but has bit 63 flipped.
+	 * This relies on set_memory_np() not checking whether we passed
+	 * a legal address.
+	 */
+
+#if PGDIR_SHIFT + 9 < 63 /* 9 because cpp doesn't grok ilog2(PTRS_PER_PGD) */
+	decoy_addr = (pfn << PAGE_SHIFT) + (PAGE_OFFSET ^ BIT(63));
+#else
+#error "no unused virtual bit available"
+#endif
+
+	if (set_memory_np(decoy_addr, 1))
+		pr_warn("Could not invalidate pfn=0x%lx from 1:1 map \n", pfn);
+
+}
+#endif
+
 /*
  * The actual machine check handler. This only handles real
  * exceptions when something got corrupted coming in through int 18.
diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h
index e030a68ead7e..25438b2b6f22 100644
--- a/include/linux/mm_inline.h
+++ b/include/linux/mm_inline.h
@@ -126,4 +126,10 @@ static __always_inline enum lru_list page_lru(struct page *page)
 
 #define lru_to_page(head) (list_entry((head)->prev, struct page, lru))
 
+#ifdef arch_unmap_kpfn
+extern void arch_unmap_kpfn(unsigned long pfn);
+#else
+static __always_inline void arch_unmap_kpfn(unsigned long pfn) { }
+#endif
+
 #endif
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 342fac9ba89b..9479e190dcbd 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -1071,6 +1071,8 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
 		return 0;
 	}
 
+	arch_unmap_kpfn(pfn);
+
 	/*
 	 * Currently errors on hugetlbfs pages are measured in hugepage units,
 	 * so nr_pages should be 1 << compound_order.  OTOH when errors are on
-- 
2.11.0

[toc] | [next] | [standalone]


#1669564 — Re: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages

FromBorislav Petkov <bp@suse.de>
Date2017-06-19 20:10 +0200
SubjectRe: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages
Message-ID<tU9hE-674-27@gated-at.bofh.it>
In reply to#1668042
(drop stable from CC)

You could use git's --suppress-cc= option when sending.

On Fri, Jun 16, 2017 at 12:02:00PM -0700, Luck, Tony wrote:
> From: Tony Luck <tony.luck@intel.com>
> 
> Speculative processor accesses may reference any memory that has a
> valid page table entry.  While a speculative access won't generate
> a machine check, it will log the error in a machine check bank. That
> could cause escalation of a subsequent error since the overflow bit
> will be then set in the machine check bank status register.

...

> @@ -1056,6 +1057,40 @@ static int do_memory_failure(struct mce *m)
>  	return ret;
>  }
>  
> +#ifdef CONFIG_X86_64
> +
> +void arch_unmap_kpfn(unsigned long pfn)
> +{

I guess you can move the ifdeffery inside the function.

> +	unsigned long decoy_addr;
> +
> +	/*
> +	 * Unmap this page from the kernel 1:1 mappings to make sure
> +	 * we don't log more errors because of speculative access to
> +	 * the page.
> +	 * We would like to just call:
> +	 *	set_memory_np((unsigned long)pfn_to_kaddr(pfn), 1);
> +	 * but doing that would radically increase the odds of a
> +	 * speculative access to the posion page because we'd have
> +	 * the virtual address of the kernel 1:1 mapping sitting
> +	 * around in registers.
> +	 * Instead we get tricky.  We create a non-canonical address
> +	 * that looks just like the one we want, but has bit 63 flipped.
> +	 * This relies on set_memory_np() not checking whether we passed
> +	 * a legal address.
> +	 */
> +
> +#if PGDIR_SHIFT + 9 < 63 /* 9 because cpp doesn't grok ilog2(PTRS_PER_PGD) */

Please no side comments.

Also, explain why the build-time check. (Sign-extension going away for VA
space yadda yadda..., 5 2/3 level paging :-))

Also, I'm assuming this whole "workaround" of sorts should be Intel-only?

> +	decoy_addr = (pfn << PAGE_SHIFT) + (PAGE_OFFSET ^ BIT(63));
> +#else
> +#error "no unused virtual bit available"
> +#endif
> +
> +	if (set_memory_np(decoy_addr, 1))
> +		pr_warn("Could not invalidate pfn=0x%lx from 1:1 map \n", pfn);

WARNING: unnecessary whitespace before a quoted newline
#107: FILE: arch/x86/kernel/cpu/mcheck/mce.c:1089:
+               pr_warn("Could not invalidate pfn=0x%lx from 1:1 map \n", pfn);


-- 
Regards/Gruss,
    Boris.

SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg)
-- 

[toc] | [prev] | [next] | [standalone]


#1671857 — Re: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages

From"Luck, Tony" <tony.luck@intel.com>
Date2017-06-21 19:50 +0200
SubjectRe: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages
Message-ID<tURVo-Rb-33@gated-at.bofh.it>
In reply to#1669564
On Mon, Jun 19, 2017 at 08:01:47PM +0200, Borislav Petkov wrote:
> (drop stable from CC)
> 
> You could use git's --suppress-cc= option when sending.

I would if I could work out how to use it. From reading the manual
page there seem to be a few options to this, but none of them appear
to just drop a specific address (apart from my own). :-(

> > +#ifdef CONFIG_X86_64
> > +
> > +void arch_unmap_kpfn(unsigned long pfn)
> > +{
> 
> I guess you can move the ifdeffery inside the function.

If I do, then the compiler will emit an empty function. It's only
a couple of bytes for the "ret" ... but why?  I may change it
to:

   #if defined(arch_unmap_kpfn) && defined(CONFIG_MEMORY_FAILURE)

to narrow down further when we need this.

> > +#if PGDIR_SHIFT + 9 < 63 /* 9 because cpp doesn't grok ilog2(PTRS_PER_PGD) */
> 
> Please no side comments.

Ok.

> Also, explain why the build-time check. (Sign-extension going away for VA
> space yadda yadda..., 5 2/3 level paging :-))

Will add.

> Also, I'm assuming this whole "workaround" of sorts should be Intel-only?

I'd assume that other X86 implementations would face similar issues (unless
they have extremely cautious pre-fetchers and/or no speculation).

I'm also assuming that non-X86 architectures that do recovery may want this
too ... hence hooking the arch_unmap_kpfn() function into the generic
memory_failure() code.

> > +	decoy_addr = (pfn << PAGE_SHIFT) + (PAGE_OFFSET ^ BIT(63));
> > +#else
> > +#error "no unused virtual bit available"
> > +#endif
> > +
> > +	if (set_memory_np(decoy_addr, 1))
> > +		pr_warn("Could not invalidate pfn=0x%lx from 1:1 map \n", pfn);
> 
> WARNING: unnecessary whitespace before a quoted newline
> #107: FILE: arch/x86/kernel/cpu/mcheck/mce.c:1089:
> +               pr_warn("Could not invalidate pfn=0x%lx from 1:1 map \n", pfn);

Oops!  Will fix.

-Tony

[toc] | [prev] | [next] | [standalone]


#1671992 — RE: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages

From"Elliott, Robert (Persistent Memory)" <elliott@hpe.com>
Date2017-06-21 22:00 +0200
SubjectRE: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages
Message-ID<tUTXb-2iv-1@gated-at.bofh.it>
In reply to#1671857
> +	decoy_addr = (pfn << PAGE_SHIFT) + (PAGE_OFFSET ^ BIT(63));
> +#else
> +#error "no unused virtual bit available"
> +#endif
> +
> +	if (set_memory_np(decoy_addr, 1))
> +		pr_warn("Could not invalidate pfn=0x%lx from 1:1 map \n", pfn);

Does this patch handle breaking up 512 GiB, 1 GiB or 2 MiB page mappings
if it's just trying to mark a 4 KiB page as bad?

Although the kernel doesn't use MTRRs itself anymore, what if the system
BIOS still uses them for some memory regions, and the bad address falls in
an MTRR region?

---
Robert Elliott, HPE Persistent Memory

[toc] | [prev] | [next] | [standalone]


#1672002 — RE: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages

From"Luck, Tony" <tony.luck@intel.com>
Date2017-06-21 22:20 +0200
SubjectRE: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages
Message-ID<tUUgx-2Hl-13@gated-at.bofh.it>
In reply to#1671992
>> +if (set_memory_np(decoy_addr, 1))
>> +pr_warn("Could not invalidate pfn=0x%lx from 1:1 map \n", pfn);
>
> Does this patch handle breaking up 512 GiB, 1 GiB or 2 MiB page mappings
> if it's just trying to mark a 4 KiB page as bad?

Yes.  The 1:1 mappings start out using the largest supported page size.  This
call will break up huge/large pages so that only 4KB is mapped out.
[This will affect performance because of the extra levels of TLB walks]

> Although the kernel doesn't use MTRRs itself anymore, what if the system
> BIOS still uses them for some memory regions, and the bad address falls in
> an MTRR region?

This code is called after mm/memory-failure.c:memory_failure() has already
checked that the page is one managed by the kernel.  In general machine checks
from other regions are going to be called out as fatal before we get here.

-Tony

[toc] | [prev] | [next] | [standalone]


#1672466 — Re: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages

FromBorislav Petkov <bp@suse.de>
Date2017-06-22 11:40 +0200
SubjectRe: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages
Message-ID<tV6KJ-2Nq-7@gated-at.bofh.it>
In reply to#1671857
On Wed, Jun 21, 2017 at 10:47:40AM -0700, Luck, Tony wrote:
> I would if I could work out how to use it. From reading the manual
> page there seem to be a few options to this, but none of them appear
> to just drop a specific address (apart from my own). :-(

$ git send-email --to ... --cc ... --cc ... --suppress-cc=all ...

That should send only to the ones you have in --to and --cc and suppress
the rest.

Do a

$ git send-email -v --dry-run --to ... --cc ... --cc ... --suppress-cc=all ...

to see what it is going to do.

> I'd assume that other X86 implementations would face similar issues (unless
> they have extremely cautious pre-fetchers and/or no speculation).
> 
> I'm also assuming that non-X86 architectures that do recovery may want this
> too ... hence hooking the arch_unmap_kpfn() function into the generic
> memory_failure() code.

Which means that you could move the function to generic
mm/memory_failure.c code after making the decoy_addr computation
generic.

I'd still like to hear some sort of confirmation from other
vendors/arches whether it makes sense for them too, though.

I mean, if they don't do speculative accesses, then it probably doesn't
matter even - the page is innacessible anyway but still...

-- 
Regards/Gruss,
    Boris.

SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg)
-- 

[toc] | [prev] | [next] | [standalone]


#1678239 — git send-email (w/o Cc: stable)

From"Luck, Tony" <tony.luck@intel.com>
Date2017-06-30 00:20 +0200
Subjectgit send-email (w/o Cc: stable)
Message-ID<tXPX4-5hd-5@gated-at.bofh.it>
In reply to#1672466
On Thu, Jun 22, 2017 at 11:39:05AM +0200, Borislav Petkov wrote:
> On Wed, Jun 21, 2017 at 10:47:40AM -0700, Luck, Tony wrote:
> > I would if I could work out how to use it. From reading the manual
> > page there seem to be a few options to this, but none of them appear
> > to just drop a specific address (apart from my own). :-(
> 
> $ git send-email --to ... --cc ... --cc ... --suppress-cc=all ...
> 
> That should send only to the ones you have in --to and --cc and suppress
> the rest.
> 
> Do a
> 
> $ git send-email -v --dry-run --to ... --cc ... --cc ... --suppress-cc=all ...
> 
> to see what it is going to do.

So there is a "--cc-cmd" option that can do the same as those "-cc" arguments.
Combine that with --suppress-cc=bodycc and things get a bit more automated.

In my .gitconfig:

[sendemail]
	suppresscc = bodycc
	ccCmd = /home/agluck/bin/sendemail.ccCmd

and the command is some sed(1) to grap the Cc: lines except the
stable@vger.kernel.org one:

sed -n \
	-e '/Cc: stable@vger.kernel.org/d' \
	-e '/^Cc: /s///p' \
	-e '/^---/q' $1

-Tony

[toc] | [prev] | [next] | [standalone]


#1678540 — Re: git send-email (w/o Cc: stable)

FromBorislav Petkov <bp@suse.de>
Date2017-06-30 09:10 +0200
SubjectRe: git send-email (w/o Cc: stable)
Message-ID<tXYdX-2mX-1@gated-at.bofh.it>
In reply to#1678239
On Thu, Jun 29, 2017 at 03:11:37PM -0700, Luck, Tony wrote:
> So there is a "--cc-cmd" option that can do the same as those "-cc" arguments.
> Combine that with --suppress-cc=bodycc and things get a bit more automated.

Yeah, whatever works for you.

I did play with cc-cmd somewhat but can't be bothered to generate the CC
list per hand each time.

I'd prefer if that switch:

	--suppress-cc=<category>

had the obvious <category> of single email address too:

	--suppress-cc=stable@vger.kernel.org

so that we can send patches and unconditionally suppress only that
single recipient from the CC list.

And maybe there is a way...

Let me CC the git ML.

-- 
Regards/Gruss,
    Boris.

SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg)
-- 

[toc] | [prev] | [next] | [standalone]


#1673924 — RE: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages

From"Elliott, Robert (Persistent Memory)" <elliott@hpe.com>
Date2017-06-24 00:30 +0200
SubjectRE: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages
Message-ID<tVFfr-80b-7@gated-at.bofh.it>
In reply to#1671857
> > > +	if (set_memory_np(decoy_addr, 1))
> > > +		pr_warn("Could not invalidate pfn=0x%lx from 1:1 map \n",

Another concept to consider is mapping the page as UC rather than
completely unmapping it.

The uncorrectable error scope could be smaller than a page size, like:
* memory ECC width (e.g., 8 bytes)
* cache line size (e.g., 64 bytes)
* block device logical block size (e.g., 512 bytes, for persistent memory)

UC preserves the ability to access adjacent data within the page that
hasn't gone bad, and is particularly useful for persistent memory.

---
Robert Elliott, HPE Persistent Memory

[toc] | [prev] | [next] | [standalone]


#1676210 — Re: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages

FromDan Williams <dan.j.williams@intel.com>
Date2017-06-28 00:10 +0200
SubjectRe: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages
Message-ID<tX6Qh-6Lo-13@gated-at.bofh.it>
In reply to#1673924
On Tue, Jun 27, 2017 at 3:04 PM, Luck, Tony <tony.luck@intel.com> wrote:
>> > > > +if (set_memory_np(decoy_addr, 1))
>> > > > +pr_warn("Could not invalidate pfn=0x%lx from 1:1 map \n",
>>
>> Another concept to consider is mapping the page as UC rather than
>> completely unmapping it.
>
> UC would also avoid the speculative prefetch issue.  The Vol 3, Section 11.3 SDM says:
>
> Strong Uncacheable (UC) -System memory locations are not cached. All reads and writes
> appear on the system bus and are executed in program order without reordering. No speculative
> memory accesses, pagetable walks, or prefetches of speculated branch targets are made.
> This type of cache-control is useful for memory-mapped I/O devices. When used with normal
> RAM, it greatly reduces processor performance.
>
> But then I went and read the code for set_memory_uc() ... which calls "reserve_memtyep()"
> which does all kinds of things to avoid issues with MTRRs and other stuff.  Which all looks
> really more complex that we need just here.
>
>> The uncorrectable error scope could be smaller than a page size, like:
>> * memory ECC width (e.g., 8 bytes)
>> * cache line size (e.g., 64 bytes)
>> * block device logical block size (e.g., 512 bytes, for persistent memory)
>>
>> UC preserves the ability to access adjacent data within the page that
>> hasn't gone bad, and is particularly useful for persistent memory.
>
> If you want to dig into the non-poisoned pieces of the page later it might be
> better to set up a new scratch UC mapping to do that.
>
> My takeaway from Dan's comments on unpoisoning is that this isn't the context
> that he wants to do that.  He'd rather wait until he has somebody overwriting the
> page with fresh data.
>
> So I think I'd like to keep the patch as-is.

Yes, the persistent-memory poison interactions should be handled
separately and not hold up this patch for the normal system-memory
case. We might dove-tail support for this into stray write protection
where we unmap all of pmem while nothing in the kernel is actively
accessing it.

[toc] | [prev] | [next] | [standalone]


#1676212 — RE: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages

From"Luck, Tony" <tony.luck@intel.com>
Date2017-06-28 00:10 +0200
SubjectRE: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages
Message-ID<tX6Qh-6Lo-15@gated-at.bofh.it>
In reply to#1673924
> > > > +if (set_memory_np(decoy_addr, 1))
> > > > +pr_warn("Could not invalidate pfn=0x%lx from 1:1 map \n",
>
> Another concept to consider is mapping the page as UC rather than
> completely unmapping it.

UC would also avoid the speculative prefetch issue.  The Vol 3, Section 11.3 SDM says:

Strong Uncacheable (UC) -System memory locations are not cached. All reads and writes
appear on the system bus and are executed in program order without reordering. No speculative
memory accesses, pagetable walks, or prefetches of speculated branch targets are made.
This type of cache-control is useful for memory-mapped I/O devices. When used with normal
RAM, it greatly reduces processor performance.

But then I went and read the code for set_memory_uc() ... which calls "reserve_memtyep()"
which does all kinds of things to avoid issues with MTRRs and other stuff.  Which all looks
really more complex that we need just here.

> The uncorrectable error scope could be smaller than a page size, like:
> * memory ECC width (e.g., 8 bytes)
> * cache line size (e.g., 64 bytes)
> * block device logical block size (e.g., 512 bytes, for persistent memory)
>
> UC preserves the ability to access adjacent data within the page that
> hasn't gone bad, and is particularly useful for persistent memory.

If you want to dig into the non-poisoned pieces of the page later it might be
better to set up a new scratch UC mapping to do that.

My takeaway from Dan's comments on unpoisoning is that this isn't the context
that he wants to do that.  He'd rather wait until he has somebody overwriting the
page with fresh data.

So I think I'd like to keep the patch as-is.

-Tony

[toc] | [prev] | [next] | [standalone]


#1671290 — Re: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages

FromNaoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Date2017-06-21 04:20 +0200
SubjectRe: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages
Message-ID<tUDpo-8t6-5@gated-at.bofh.it>
In reply to#1668042
(drop stable from CC)

On Fri, Jun 16, 2017 at 12:02:00PM -0700, Luck, Tony wrote:
> From: Tony Luck <tony.luck@intel.com>
> 
> Speculative processor accesses may reference any memory that has a
> valid page table entry.  While a speculative access won't generate
> a machine check, it will log the error in a machine check bank. That
> could cause escalation of a subsequent error since the overflow bit
> will be then set in the machine check bank status register.
> 
> Code has to be double-plus-tricky to avoid mentioning the 1:1 virtual
> address of the page we want to map out otherwise we may trigger the
> very problem we are trying to avoid.  We use a non-canonical address
> that passes through the usual Linux table walking code to get to the
> same "pte".
> 
> Cc: Dave Hansen <dave.hansen@intel.com>
> Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
> Cc: x86@kernel.org
> Cc: linux-mm@kvack.org
> Cc: linux-kernel@vger.kernel.org
> Cc: stable@vger.kernel.org
> Signed-off-by: Tony Luck <tony.luck@intel.com>
> ---
> Thanks to Dave Hansen for reviewing several iterations of this.
> 
>  arch/x86/include/asm/page_64.h   |  4 ++++
>  arch/x86/kernel/cpu/mcheck/mce.c | 35 +++++++++++++++++++++++++++++++++++
>  include/linux/mm_inline.h        |  6 ++++++
>  mm/memory-failure.c              |  2 ++
>  4 files changed, 47 insertions(+)
> 
> diff --git a/arch/x86/include/asm/page_64.h b/arch/x86/include/asm/page_64.h
> index b4a0d43248cf..b50df06ad251 100644
> --- a/arch/x86/include/asm/page_64.h
> +++ b/arch/x86/include/asm/page_64.h
> @@ -51,6 +51,10 @@ static inline void clear_page(void *page)
>  
>  void copy_page(void *to, void *from);
>  
> +#ifdef CONFIG_X86_MCE
> +#define arch_unmap_kpfn arch_unmap_kpfn
> +#endif
> +
>  #endif	/* !__ASSEMBLY__ */
>  
>  #ifdef CONFIG_X86_VSYSCALL_EMULATION
> diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
> index 5cfbaeb6529a..56563db0b2be 100644
> --- a/arch/x86/kernel/cpu/mcheck/mce.c
> +++ b/arch/x86/kernel/cpu/mcheck/mce.c
> @@ -51,6 +51,7 @@
>  #include <asm/mce.h>
>  #include <asm/msr.h>
>  #include <asm/reboot.h>
> +#include <asm/set_memory.h>
>  
>  #include "mce-internal.h"
>  
> @@ -1056,6 +1057,40 @@ static int do_memory_failure(struct mce *m)
>  	return ret;
>  }
>  
> +#ifdef CONFIG_X86_64
> +
> +void arch_unmap_kpfn(unsigned long pfn)
> +{
> +	unsigned long decoy_addr;
> +
> +	/*
> +	 * Unmap this page from the kernel 1:1 mappings to make sure
> +	 * we don't log more errors because of speculative access to
> +	 * the page.
> +	 * We would like to just call:
> +	 *	set_memory_np((unsigned long)pfn_to_kaddr(pfn), 1);
> +	 * but doing that would radically increase the odds of a
> +	 * speculative access to the posion page because we'd have
> +	 * the virtual address of the kernel 1:1 mapping sitting
> +	 * around in registers.
> +	 * Instead we get tricky.  We create a non-canonical address
> +	 * that looks just like the one we want, but has bit 63 flipped.
> +	 * This relies on set_memory_np() not checking whether we passed
> +	 * a legal address.
> +	 */
> +
> +#if PGDIR_SHIFT + 9 < 63 /* 9 because cpp doesn't grok ilog2(PTRS_PER_PGD) */
> +	decoy_addr = (pfn << PAGE_SHIFT) + (PAGE_OFFSET ^ BIT(63));
> +#else
> +#error "no unused virtual bit available"
> +#endif
> +
> +	if (set_memory_np(decoy_addr, 1))
> +		pr_warn("Could not invalidate pfn=0x%lx from 1:1 map \n", pfn);
> +
> +}
> +#endif
> +
>  /*
>   * The actual machine check handler. This only handles real
>   * exceptions when something got corrupted coming in through int 18.
> diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h
> index e030a68ead7e..25438b2b6f22 100644
> --- a/include/linux/mm_inline.h
> +++ b/include/linux/mm_inline.h
> @@ -126,4 +126,10 @@ static __always_inline enum lru_list page_lru(struct page *page)
>  
>  #define lru_to_page(head) (list_entry((head)->prev, struct page, lru))
>  
> +#ifdef arch_unmap_kpfn
> +extern void arch_unmap_kpfn(unsigned long pfn);
> +#else
> +static __always_inline void arch_unmap_kpfn(unsigned long pfn) { }
> +#endif
> +
>  #endif
> diff --git a/mm/memory-failure.c b/mm/memory-failure.c
> index 342fac9ba89b..9479e190dcbd 100644
> --- a/mm/memory-failure.c
> +++ b/mm/memory-failure.c
> @@ -1071,6 +1071,8 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
>  		return 0;
>  	}
>  
> +	arch_unmap_kpfn(pfn);
> +

We had better have a reverse operation of this to cancel the unmapping
when unpoisoning?

Thanks,
Naoya Horiguchi

[toc] | [prev] | [next] | [standalone]


#1671862 — Re: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages

From"Luck, Tony" <tony.luck@intel.com>
Date2017-06-21 20:00 +0200
SubjectRe: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages
Message-ID<tUS54-VR-21@gated-at.bofh.it>
In reply to#1671290
On Wed, Jun 21, 2017 at 02:12:27AM +0000, Naoya Horiguchi wrote:

> We had better have a reverse operation of this to cancel the unmapping
> when unpoisoning?

When we have unpoisoning, we can add something.  We don't seem to have
an inverse function for "set_memory_np" to just flip the _PRESENT bit
back on again. But it would be trivial to write a set_memory_pp().

Since we'd be doing this after the poison has been cleared, we wouldn't
need to play games with the address.  We'd just use:

	set_memory_pp((unsigned long)pfn_to_kaddr(pfn), 1);

-Tony

[toc] | [prev] | [next] | [standalone]


#1671991 — RE: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages

From"Elliott, Robert (Persistent Memory)" <elliott@hpe.com>
Date2017-06-21 21:50 +0200
SubjectRE: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages
Message-ID<tUTNw-2eb-9@gated-at.bofh.it>
In reply to#1671862
> -----Original Message-----
> From: linux-kernel-owner@vger.kernel.org [mailto:linux-kernel-
> owner@vger.kernel.org] On Behalf Of Luck, Tony
> Sent: Wednesday, June 21, 2017 12:54 PM
> To: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
> Cc: Borislav Petkov <bp@suse.de>; Dave Hansen <dave.hansen@intel.com>;
> x86@kernel.org; linux-mm@kvack.org; linux-kernel@vger.kernel.org

(adding linux-nvdimm list in this reply)

> Subject: Re: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1
> mappings of poison pages
> 
> On Wed, Jun 21, 2017 at 02:12:27AM +0000, Naoya Horiguchi wrote:
> 
> > We had better have a reverse operation of this to cancel the unmapping
> > when unpoisoning?
> 
> When we have unpoisoning, we can add something.  We don't seem to have
> an inverse function for "set_memory_np" to just flip the _PRESENT bit
> back on again. But it would be trivial to write a set_memory_pp().
> 
> Since we'd be doing this after the poison has been cleared, we wouldn't
> need to play games with the address.  We'd just use:
> 
> 	set_memory_pp((unsigned long)pfn_to_kaddr(pfn), 1);
> 
> -Tony

Persistent memory does have unpoisoning and would require this inverse
operation - see drivers/nvdimm/pmem.c pmem_clear_poison() and core.c
nvdimm_clear_poison().

---
Robert Elliott, HPE Persistent Memory

[toc] | [prev] | [next] | [standalone]


#1672015 — RE: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages

From"Luck, Tony" <tony.luck@intel.com>
Date2017-06-21 22:40 +0200
SubjectRE: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages
Message-ID<tUUzU-2OU-15@gated-at.bofh.it>
In reply to#1671991
> Persistent memory does have unpoisoning and would require this inverse
> operation - see drivers/nvdimm/pmem.c pmem_clear_poison() and core.c
> nvdimm_clear_poison().

Nice.  Well this code will need to cooperate with that ... in particular if the page
is in an area that can be unpoisoned ... then we should do that *instead* of marking
the page not present (which breaks up huge/large pages and so affects performance).

Instead of calling it "arch_unmap_pfn" it could be called something like arch_handle_poison()
and do something like:

void arch_handle_poison(unsigned long pfn)
{
	if this is a pmem page && pmem_clear_poison(pfn)
		return
	if this is a nvdimm page && nvdimm_clear_poison(pfn)
		return
	/* can't clear, map out from 1:1 region */
	... code from my patch ...
}

I'm just not sure how those first two "if" bits work ... particularly in terms of CONFIG dependencies and system
capabilities.  Perhaps each of pmem and nvdimm could register their unpoison functions and this code could
just call each in turn?

-Tony

[toc] | [prev] | [next] | [standalone]


#1673253 — Re: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages

FromDan Williams <dan.j.williams@intel.com>
Date2017-06-23 07:10 +0200
SubjectRe: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages
Message-ID<tVp0Z-6lw-13@gated-at.bofh.it>
In reply to#1672015
On Wed, Jun 21, 2017 at 1:30 PM, Luck, Tony <tony.luck@intel.com> wrote:
>> Persistent memory does have unpoisoning and would require this inverse
>> operation - see drivers/nvdimm/pmem.c pmem_clear_poison() and core.c
>> nvdimm_clear_poison().
>
> Nice.  Well this code will need to cooperate with that ... in particular if the page
> is in an area that can be unpoisoned ... then we should do that *instead* of marking
> the page not present (which breaks up huge/large pages and so affects performance).
>
> Instead of calling it "arch_unmap_pfn" it could be called something like arch_handle_poison()
> and do something like:
>
> void arch_handle_poison(unsigned long pfn)
> {
>         if this is a pmem page && pmem_clear_poison(pfn)
>                 return
>         if this is a nvdimm page && nvdimm_clear_poison(pfn)
>                 return
>         /* can't clear, map out from 1:1 region */
>         ... code from my patch ...
> }
>
> I'm just not sure how those first two "if" bits work ... particularly in terms of CONFIG dependencies and system
> capabilities.  Perhaps each of pmem and nvdimm could register their unpoison functions and this code could
> just call each in turn?

We don't unpoison pmem without new data to write in it's place. What
context is arch_handle_poison() called? Ideally we only "clear" poison
when we know we are trying to write zero over the poisoned range.

[toc] | [prev] | [next] | [standalone]


#1673866 — Re: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages

From"Luck, Tony" <tony.luck@intel.com>
Date2017-06-23 23:00 +0200
SubjectRe: [PATCH] mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages
Message-ID<tVDQl-6YI-7@gated-at.bofh.it>
In reply to#1673253
On Thu, Jun 22, 2017 at 10:07:18PM -0700, Dan Williams wrote:
> On Wed, Jun 21, 2017 at 1:30 PM, Luck, Tony <tony.luck@intel.com> wrote:
> >> Persistent memory does have unpoisoning and would require this inverse
> >> operation - see drivers/nvdimm/pmem.c pmem_clear_poison() and core.c
> >> nvdimm_clear_poison().
> >
> > Nice.  Well this code will need to cooperate with that ... in particular if the page
> > is in an area that can be unpoisoned ... then we should do that *instead* of marking
> > the page not present (which breaks up huge/large pages and so affects performance).
> >
> > Instead of calling it "arch_unmap_pfn" it could be called something like arch_handle_poison()
> > and do something like:
> >
> > void arch_handle_poison(unsigned long pfn)
> > {
> >         if this is a pmem page && pmem_clear_poison(pfn)
> >                 return
> >         if this is a nvdimm page && nvdimm_clear_poison(pfn)
> >                 return
> >         /* can't clear, map out from 1:1 region */
> >         ... code from my patch ...
> > }
> >
> > I'm just not sure how those first two "if" bits work ... particularly in terms of CONFIG dependencies and system
> > capabilities.  Perhaps each of pmem and nvdimm could register their unpoison functions and this code could
> > just call each in turn?
> 
> We don't unpoison pmem without new data to write in it's place. What
> context is arch_handle_poison() called? Ideally we only "clear" poison
> when we know we are trying to write zero over the poisoned range.

Context is that of the process that did the access (but we've moved
off the machine check stack and are now in normal kernel context).
We are about to unmap this page from all applications that are
using it.  But they may be running ... so now it a bad time to
clear the poison. They might access the page and not get a signal.

If I move this code to after all the users PTEs have been cleared
and TLBs flushed, then it would be safe to try to unpoison the page
and not invalidate from the 1:1 mapping.

But I'm not sure what happens next. For a normal DDR4 page I could
put it back on the free list and allow it to be re-used. But for
PMEM you have some other cleanup that you need to do to mark the
block as lost from your file system.

Is this too early for you to be able to do that?

-Tony

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web