summaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2019-07-11 23:57:28 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-07-12 14:05:45 -0400
commitcbd34da7dc9afd521e0bea5e7d12701f4a9da7c7 (patch)
tree01134464a578f6e5ec091a739b3671528eaf3d54 /mm
parent817be129e6f254e5bd8c17b1da834c8f612dca28 (diff)
mm: move the powerpc hugepd code to mm/gup.c
While only powerpc supports the hugepd case, the code is pretty generic and I'd like to keep all GUP internals in one place. Link: http://lkml.kernel.org/r/20190625143715.1689-15-hch@lst.de Signed-off-by: Christoph Hellwig <hch@lst.de> Cc: Andrey Konovalov <andreyknvl@google.com> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: David Miller <davem@davemloft.net> Cc: James Hogan <jhogan@kernel.org> Cc: Jason Gunthorpe <jgg@mellanox.com> Cc: Khalid Aziz <khalid.aziz@oracle.com> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Nicholas Piggin <npiggin@gmail.com> Cc: Paul Burton <paul.burton@mips.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Ralf Baechle <ralf@linux-mips.org> Cc: Rich Felker <dalias@libc.org> Cc: Yoshinori Sato <ysato@users.sourceforge.jp> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/Kconfig10
-rw-r--r--mm/gup.c82
2 files changed, 92 insertions, 0 deletions
diff --git a/mm/Kconfig b/mm/Kconfig
index 48840b28482b..0b4352557dd5 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -769,4 +769,14 @@ config GUP_GET_PTE_LOW_HIGH
769config ARCH_HAS_PTE_SPECIAL 769config ARCH_HAS_PTE_SPECIAL
770 bool 770 bool
771 771
772#
773# Some architectures require a special hugepage directory format that is
774# required to support multiple hugepage sizes. For example a4fe3ce76
775# "powerpc/mm: Allow more flexible layouts for hugepage pagetables"
776# introduced it on powerpc. This allows for a more flexible hugepage
777# pagetable layouts.
778#
779config ARCH_HAS_HUGEPD
780 bool
781
772endmenu 782endmenu
diff --git a/mm/gup.c b/mm/gup.c
index 9d68cef2fa90..2f8bf7a71c74 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -1966,6 +1966,88 @@ static int __gup_device_huge_pud(pud_t pud, pud_t *pudp, unsigned long addr,
1966} 1966}
1967#endif 1967#endif
1968 1968
1969#ifdef CONFIG_ARCH_HAS_HUGEPD
1970static unsigned long hugepte_addr_end(unsigned long addr, unsigned long end,
1971 unsigned long sz)
1972{
1973 unsigned long __boundary = (addr + sz) & ~(sz-1);
1974 return (__boundary - 1 < end - 1) ? __boundary : end;
1975}
1976
1977static int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long addr,
1978 unsigned long end, int write, struct page **pages, int *nr)
1979{
1980 unsigned long pte_end;
1981 struct page *head, *page;
1982 pte_t pte;
1983 int refs;
1984
1985 pte_end = (addr + sz) & ~(sz-1);
1986 if (pte_end < end)
1987 end = pte_end;
1988
1989 pte = READ_ONCE(*ptep);
1990
1991 if (!pte_access_permitted(pte, write))
1992 return 0;
1993
1994 /* hugepages are never "special" */
1995 VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
1996
1997 refs = 0;
1998 head = pte_page(pte);
1999
2000 page = head + ((addr & (sz-1)) >> PAGE_SHIFT);
2001 do {
2002 VM_BUG_ON(compound_head(page) != head);
2003 pages[*nr] = page;
2004 (*nr)++;
2005 page++;
2006 refs++;
2007 } while (addr += PAGE_SIZE, addr != end);
2008
2009 if (!page_cache_add_speculative(head, refs)) {
2010 *nr -= refs;
2011 return 0;
2012 }
2013
2014 if (unlikely(pte_val(pte) != pte_val(*ptep))) {
2015 /* Could be optimized better */
2016 *nr -= refs;
2017 while (refs--)
2018 put_page(head);
2019 return 0;
2020 }
2021
2022 return 1;
2023}
2024
2025static int gup_huge_pd(hugepd_t hugepd, unsigned long addr,
2026 unsigned int pdshift, unsigned long end, int write,
2027 struct page **pages, int *nr)
2028{
2029 pte_t *ptep;
2030 unsigned long sz = 1UL << hugepd_shift(hugepd);
2031 unsigned long next;
2032
2033 ptep = hugepte_offset(hugepd, addr, pdshift);
2034 do {
2035 next = hugepte_addr_end(addr, end, sz);
2036 if (!gup_hugepte(ptep, sz, addr, end, write, pages, nr))
2037 return 0;
2038 } while (ptep++, addr = next, addr != end);
2039
2040 return 1;
2041}
2042#else
2043static inline int gup_huge_pd(hugepd_t hugepd, unsigned long addr,
2044 unsigned pdshift, unsigned long end, int write,
2045 struct page **pages, int *nr)
2046{
2047 return 0;
2048}
2049#endif /* CONFIG_ARCH_HAS_HUGEPD */
2050
1969static int gup_huge_pmd(pmd_t orig, pmd_t *pmdp, unsigned long addr, 2051static int gup_huge_pmd(pmd_t orig, pmd_t *pmdp, unsigned long addr,
1970 unsigned long end, unsigned int flags, struct page **pages, int *nr) 2052 unsigned long end, unsigned int flags, struct page **pages, int *nr)
1971{ 2053{