From: Peter Zijlstra <peterz@infradead.org>
To: Linus Torvalds <torvalds@linux-foundation.org>,
paulmck <paulmck@linux.vnet.ibm.com>,
Hugh Dickins <hughd@google.com>
Cc: Rik van Riel <riel@redhat.com>,
Andrew Morton <akpm@linux-foundation.org>,
Nick Piggin <npiggin@kernel.dk>,
linux-kernel <linux-kernel@vger.kernel.org>,
Andrea Arcangeli <aarcange@redhat.com>,
linux-arch <linux-arch@vger.kernel.org>,
"linux-mm@kvack.org" <linux-mm@kvack.org>
Subject: [RFC] page-table walkers vs memory order
Date: Mon, 23 Jul 2012 19:34:30 +0200 [thread overview]
Message-ID: <1343064870.26034.23.camel@twins> (raw)
While staring at mm/huge_memory.c I found a very under-commented
smp_wmb() in __split_huge_page_map(). It turns out that its copied from
__{pte,pmd,pud}_alloc() but forgot the useful comment (or a reference
thereto).
Now, afaict we're not good, as per that comment. Paul has since
convinced some of us that compiler writers are pure evil and out to get
us.
Therefore we should do what rcu_dereference() does and use
ACCESS_ONCE()/barrier() followed smp_read_barrier_depends() every time
we dereference a page-table pointer.
In particular it looks like things like
mm/memcontrol.c:mem_cgroup_count_precharge(), which use
walk_page_range() under down_read(&mm->mmap_sem) and can thus be
concurrent with __{pte,pmd,pud}_alloc() from faults (and possibly
itself) are quite broken on Alpha and subtly broken for those of us with
'creative' compilers.
Should I go do a more extensive audit of page-table walkers or are we
happy with the status quo?
---
arch/x86/mm/gup.c | 6 +++---
mm/pagewalk.c | 24 ++++++++++++++++++++++++
2 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/arch/x86/mm/gup.c b/arch/x86/mm/gup.c
index dd74e46..4958fb1 100644
--- a/arch/x86/mm/gup.c
+++ b/arch/x86/mm/gup.c
@@ -150,7 +150,7 @@ static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
pmdp = pmd_offset(&pud, addr);
do {
- pmd_t pmd = *pmdp;
+ pmd_t pmd = ACCESS_ONCE(*pmdp);
next = pmd_addr_end(addr, end);
/*
@@ -220,7 +220,7 @@ static int gup_pud_range(pgd_t pgd, unsigned long addr, unsigned long end,
pudp = pud_offset(&pgd, addr);
do {
- pud_t pud = *pudp;
+ pud_t pud = ACCESS_ONCE(*pudp);
next = pud_addr_end(addr, end);
if (pud_none(pud))
@@ -280,7 +280,7 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
local_irq_save(flags);
pgdp = pgd_offset(mm, addr);
do {
- pgd_t pgd = *pgdp;
+ pgd_t pgd = ACCESS_ONCE(*pgdp);
next = pgd_addr_end(addr, end);
if (pgd_none(pgd))
diff --git a/mm/pagewalk.c b/mm/pagewalk.c
index 6c118d0..2ba2a74 100644
--- a/mm/pagewalk.c
+++ b/mm/pagewalk.c
@@ -10,6 +10,14 @@ static int walk_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
int err = 0;
pte = pte_offset_map(pmd, addr);
+ /*
+ * Pairs with the smp_wmb() in __{pte,pmd,pud}_alloc() and
+ * __split_huge_page_map(). Ideally we'd use ACCESS_ONCE() on the
+ * actual dereference of p[gum]d, but that's hidden deep within the
+ * bowels of {pte,pmd,pud}_offset.
+ */
+ barrier();
+ smp_read_barrier_depends();
for (;;) {
err = walk->pte_entry(pte, addr, addr + PAGE_SIZE, walk);
if (err)
@@ -32,6 +40,14 @@ static int walk_pmd_range(pud_t *pud, unsigned long addr, unsigned long end,
int err = 0;
pmd = pmd_offset(pud, addr);
+ /*
+ * Pairs with the smp_wmb() in __{pte,pmd,pud}_alloc() and
+ * __split_huge_page_map(). Ideally we'd use ACCESS_ONCE() on the
+ * actual dereference of p[gum]d, but that's hidden deep within the
+ * bowels of {pte,pmd,pud}_offset.
+ */
+ barrier();
+ smp_read_barrier_depends();
do {
again:
next = pmd_addr_end(addr, end);
@@ -77,6 +93,14 @@ static int walk_pud_range(pgd_t *pgd, unsigned long addr, unsigned long end,
int err = 0;
pud = pud_offset(pgd, addr);
+ /*
+ * Pairs with the smp_wmb() in __{pte,pmd,pud}_alloc() and
+ * __split_huge_page_map(). Ideally we'd use ACCESS_ONCE() on the
+ * actual dereference of p[gum]d, but that's hidden deep within the
+ * bowels of {pte,pmd,pud}_offset.
+ */
+ barrier();
+ smp_read_barrier_depends();
do {
next = pud_addr_end(addr, end);
if (pud_none_or_clear_bad(pud)) {
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
next reply other threads:[~2012-07-23 17:34 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-07-23 17:34 Peter Zijlstra [this message]
2012-07-23 19:27 ` [RFC] page-table walkers vs memory order Paul E. McKenney
2012-07-24 21:51 ` Hugh Dickins
2012-07-25 17:56 ` Paul E. McKenney
2012-07-25 20:26 ` Hugh Dickins
2012-07-25 21:12 ` Paul E. McKenney
2012-07-25 22:09 ` Hugh Dickins
2012-07-25 22:37 ` Paul E. McKenney
2012-07-26 8:11 ` Peter Zijlstra
2012-07-30 19:21 ` Jamie Lokier
2012-07-30 20:28 ` Paul E. McKenney
2012-07-26 20:39 ` Peter Zijlstra
2012-07-27 19:22 ` Hugh Dickins
2012-07-27 19:39 ` Paul E. McKenney
2012-08-04 14:37 ` Andrea Arcangeli
2012-08-04 22:02 ` Paul E. McKenney
2012-08-04 22:47 ` Andrea Arcangeli
2012-08-04 22:59 ` Dr. David Alan Gilbert
2012-08-04 23:11 ` Paul E. McKenney
2012-08-05 0:10 ` Dr. David Alan Gilbert
2012-08-04 23:06 ` Paul E. McKenney
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=1343064870.26034.23.camel@twins \
--to=peterz@infradead.org \
--cc=aarcange@redhat.com \
--cc=akpm@linux-foundation.org \
--cc=hughd@google.com \
--cc=linux-arch@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=npiggin@kernel.dk \
--cc=paulmck@linux.vnet.ibm.com \
--cc=riel@redhat.com \
--cc=torvalds@linux-foundation.org \
/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;
as well as URLs for NNTP newsgroup(s).