linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH V2] ARM: mm: make UACCESS_WITH_MEMCPY huge page aware
@ 2013-09-25 12:31 Steve Capper
  2013-10-11  9:57 ` Russell King - ARM Linux
  0 siblings, 1 reply; 4+ messages in thread
From: Steve Capper @ 2013-09-25 12:31 UTC (permalink / raw)
  To: linux-arm-kernel

The memory pinning code in uaccess_with_memcpy.c does not check
for HugeTLB or THP pmds, and will enter an infinite loop should
a __copy_to_user or __clear_user occur against a huge page.

This patch adds detection code for huge pages to pin_page_for_write.
As this code can be executed in a fast path it refers to the actual
pmds rather than the vma. If a HugeTLB or THP is found (they have
the same pmd representation on ARM), the page table spinlock is
taken to prevent modification whilst the page is pinned.

On ARM, huge pages are only represented as pmds, thus no huge pud
checks are performed. (For huge puds one would lock the page table
in a similar manner as in the pmd case).

Two helper functions are introduced; pmd_thp_or_huge will check
whether or not a page is huge or transparent huge (which have the
same pmd layout on ARM), and pmd_hugewillfault will detect whether
or not a page fault will occur on write to the page.

Running the following test (with the chunking from read_zero
removed):
 $ dd if=/dev/zero of=/dev/null bs=10M count=1024
Gave:  2.3 GB/s backed by normal pages,
       2.9 GB/s backed by huge pages,
       5.1 GB/s backed by huge pages, with page mask=HPAGE_MASK.

After some discussion, it was decided not to adopt the HPAGE_MASK,
as this would have a significant detrimental effect on the overall
system latency due to page_table_lock being held for too long.
This could be revisited if split huge page locks are adopted.

Signed-off-by: Steve Capper <steve.capper@linaro.org>
Reviewed-by: Nicolas Pitre <nico@linaro.org>
---
 arch/arm/include/asm/pgtable-3level.h |  3 +++
 arch/arm/lib/uaccess_with_memcpy.c    | 41 ++++++++++++++++++++++++++++++++---
 2 files changed, 41 insertions(+), 3 deletions(-)

diff --git a/arch/arm/include/asm/pgtable-3level.h b/arch/arm/include/asm/pgtable-3level.h
index 5689c18..39c54cf 100644
--- a/arch/arm/include/asm/pgtable-3level.h
+++ b/arch/arm/include/asm/pgtable-3level.h
@@ -206,6 +206,9 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)
 #define __HAVE_ARCH_PMD_WRITE
 #define pmd_write(pmd)		(!(pmd_val(pmd) & PMD_SECT_RDONLY))
 
+#define pmd_hugewillfault(pmd)	(!pmd_young(pmd) || !pmd_write(pmd))
+#define pmd_thp_or_huge(pmd)	(pmd_huge(pmd) || pmd_trans_huge(pmd))
+
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 #define pmd_trans_huge(pmd)	(pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT))
 #define pmd_trans_splitting(pmd) (pmd_val(pmd) & PMD_SECT_SPLITTING)
diff --git a/arch/arm/lib/uaccess_with_memcpy.c b/arch/arm/lib/uaccess_with_memcpy.c
index 025f742..3e58d71 100644
--- a/arch/arm/lib/uaccess_with_memcpy.c
+++ b/arch/arm/lib/uaccess_with_memcpy.c
@@ -18,6 +18,7 @@
 #include <linux/hardirq.h> /* for in_atomic() */
 #include <linux/gfp.h>
 #include <linux/highmem.h>
+#include <linux/hugetlb.h>
 #include <asm/current.h>
 #include <asm/page.h>
 
@@ -40,7 +41,35 @@ pin_page_for_write(const void __user *_addr, pte_t **ptep, spinlock_t **ptlp)
 		return 0;
 
 	pmd = pmd_offset(pud, addr);
-	if (unlikely(pmd_none(*pmd) || pmd_bad(*pmd)))
+	if (unlikely(pmd_none(*pmd)))
+		return 0;
+
+	/*
+	 * A pmd can be bad if it refers to a HugeTLB or THP page.
+	 *
+	 * Both THP and HugeTLB pages have the same pmd layout
+	 * and should not be manipulated by the pte functions.
+	 *
+	 * Lock the page table for the destination and check
+	 * to see that it's still huge and whether or not we will
+	 * need to fault on write, or if we have a splitting THP.
+	 */
+	if (unlikely(pmd_thp_or_huge(*pmd))) {
+		ptl = &current->mm->page_table_lock;
+		spin_lock(ptl);
+		if (unlikely(!pmd_thp_or_huge(*pmd)
+			|| pmd_hugewillfault(*pmd)
+			|| pmd_trans_splitting(*pmd))) {
+			spin_unlock(ptl);
+			return 0;
+		}
+
+		*ptep = NULL;
+		*ptlp = ptl;
+		return 1;
+	}
+
+	if (unlikely(pmd_bad(*pmd)))
 		return 0;
 
 	pte = pte_offset_map_lock(current->mm, pmd, addr, &ptl);
@@ -94,7 +123,10 @@ __copy_to_user_memcpy(void __user *to, const void *from, unsigned long n)
 		from += tocopy;
 		n -= tocopy;
 
-		pte_unmap_unlock(pte, ptl);
+		if (pte)
+			pte_unmap_unlock(pte, ptl);
+		else
+			spin_unlock(ptl);
 	}
 	if (!atomic)
 		up_read(&current->mm->mmap_sem);
@@ -147,7 +179,10 @@ __clear_user_memset(void __user *addr, unsigned long n)
 		addr += tocopy;
 		n -= tocopy;
 
-		pte_unmap_unlock(pte, ptl);
+		if (pte)
+			pte_unmap_unlock(pte, ptl);
+		else
+			spin_unlock(ptl);
 	}
 	up_read(&current->mm->mmap_sem);
 
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH V2] ARM: mm: make UACCESS_WITH_MEMCPY huge page aware
  2013-09-25 12:31 [PATCH V2] ARM: mm: make UACCESS_WITH_MEMCPY huge page aware Steve Capper
@ 2013-10-11  9:57 ` Russell King - ARM Linux
  2013-10-11 10:11   ` Steve Capper
  0 siblings, 1 reply; 4+ messages in thread
From: Russell King - ARM Linux @ 2013-10-11  9:57 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Sep 25, 2013 at 01:31:29PM +0100, Steve Capper wrote:
> The memory pinning code in uaccess_with_memcpy.c does not check
> for HugeTLB or THP pmds, and will enter an infinite loop should
> a __copy_to_user or __clear_user occur against a huge page.

This patch causes a build error with certain configuration options:

arch/arm/lib/uaccess_with_memcpy.c: In function 'pin_page_for_write':
arch/arm/lib/uaccess_with_memcpy.c:57:2: error: implicit declaration of function 'pmd_thp_or_huge'
arch/arm/lib/uaccess_with_memcpy.c:60:3: error: implicit declaration of function 'pmd_hugewillfault'

found via a randconfig build, configuration:

http://www.arm.linux.org.uk/developer/build/file.php?type=config&idx=6265

> ---
>  arch/arm/include/asm/pgtable-3level.h |  3 +++
>  arch/arm/lib/uaccess_with_memcpy.c    | 41 ++++++++++++++++++++++++++++++++---
>  2 files changed, 41 insertions(+), 3 deletions(-)

As the macros are in pgtable-3level.h, this won't work with any configuration
using the 2level header file.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH V2] ARM: mm: make UACCESS_WITH_MEMCPY huge page aware
  2013-10-11  9:57 ` Russell King - ARM Linux
@ 2013-10-11 10:11   ` Steve Capper
  2013-10-11 10:37     ` Russell King - ARM Linux
  0 siblings, 1 reply; 4+ messages in thread
From: Steve Capper @ 2013-10-11 10:11 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Oct 11, 2013 at 10:57:51AM +0100, Russell King - ARM Linux wrote:
> On Wed, Sep 25, 2013 at 01:31:29PM +0100, Steve Capper wrote:
> > The memory pinning code in uaccess_with_memcpy.c does not check
> > for HugeTLB or THP pmds, and will enter an infinite loop should
> > a __copy_to_user or __clear_user occur against a huge page.
> 
> This patch causes a build error with certain configuration options:
> 
> arch/arm/lib/uaccess_with_memcpy.c: In function 'pin_page_for_write':
> arch/arm/lib/uaccess_with_memcpy.c:57:2: error: implicit declaration of function 'pmd_thp_or_huge'
> arch/arm/lib/uaccess_with_memcpy.c:60:3: error: implicit declaration of function 'pmd_hugewillfault'
> 
> found via a randconfig build, configuration:
> 
> http://www.arm.linux.org.uk/developer/build/file.php?type=config&idx=6265
> 
> > ---
> >  arch/arm/include/asm/pgtable-3level.h |  3 +++
> >  arch/arm/lib/uaccess_with_memcpy.c    | 41 ++++++++++++++++++++++++++++++++---
> >  2 files changed, 41 insertions(+), 3 deletions(-)
> 
> As the macros are in pgtable-3level.h, this won't work with any configuration
> using the 2level header file.

Hi Russell,
Apologies, that was careless rebasing on my part.

Would you like a fix for this, or should I send a new patch?

Thanks,
-- 
Steve

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH V2] ARM: mm: make UACCESS_WITH_MEMCPY huge page aware
  2013-10-11 10:11   ` Steve Capper
@ 2013-10-11 10:37     ` Russell King - ARM Linux
  0 siblings, 0 replies; 4+ messages in thread
From: Russell King - ARM Linux @ 2013-10-11 10:37 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Oct 11, 2013 at 11:11:32AM +0100, Steve Capper wrote:
> On Fri, Oct 11, 2013 at 10:57:51AM +0100, Russell King - ARM Linux wrote:
> > On Wed, Sep 25, 2013 at 01:31:29PM +0100, Steve Capper wrote:
> > > The memory pinning code in uaccess_with_memcpy.c does not check
> > > for HugeTLB or THP pmds, and will enter an infinite loop should
> > > a __copy_to_user or __clear_user occur against a huge page.
> > 
> > This patch causes a build error with certain configuration options:
> > 
> > arch/arm/lib/uaccess_with_memcpy.c: In function 'pin_page_for_write':
> > arch/arm/lib/uaccess_with_memcpy.c:57:2: error: implicit declaration of function 'pmd_thp_or_huge'
> > arch/arm/lib/uaccess_with_memcpy.c:60:3: error: implicit declaration of function 'pmd_hugewillfault'
> > 
> > found via a randconfig build, configuration:
> > 
> > http://www.arm.linux.org.uk/developer/build/file.php?type=config&idx=6265
> > 
> > > ---
> > >  arch/arm/include/asm/pgtable-3level.h |  3 +++
> > >  arch/arm/lib/uaccess_with_memcpy.c    | 41 ++++++++++++++++++++++++++++++++---
> > >  2 files changed, 41 insertions(+), 3 deletions(-)
> > 
> > As the macros are in pgtable-3level.h, this won't work with any configuration
> > using the 2level header file.
> 
> Hi Russell,
> Apologies, that was careless rebasing on my part.
> 
> Would you like a fix for this, or should I send a new patch?

I'd prefer a new patch please.

Thanks.

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2013-10-11 10:37 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-09-25 12:31 [PATCH V2] ARM: mm: make UACCESS_WITH_MEMCPY huge page aware Steve Capper
2013-10-11  9:57 ` Russell King - ARM Linux
2013-10-11 10:11   ` Steve Capper
2013-10-11 10:37     ` Russell King - ARM Linux

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).